Shell-Erweiterung (A | B) in Dateinamen?

9

Ist es möglich, eine orAuswahl in der Shell zu erweitern, wenn Sie beispielsweise eine Datei lesen?

Damit meine ich, dass beispielsweise grepdie Syntax unterstützt wird , die (A|B)A oder B in einer Datei entspricht.

Ebenso, wenn ich diese Dateien habe:

file1.txt
file2.txt
file3.txt
file4.txt
file5.txt

Ich konnte tun cat file{1..5}.txtin bash, wie es um den Bereich erweitert. Gibt es eine äquivalente Möglichkeit, dies nur für ein paar Dateien zu tun?

ZB cat file(1|5).txtund nur diese 2 drucken?

Joe Healey
quelle

Antworten:

16

Das Standard-Globbing-Muster für Dateinamen, das mit einer Ziffer übereinstimmt, lautet [0-9]. Dies entspricht einer einzelnen Ziffer:

cat file[0-9].txt

So wählen Sie nur zwei davon aus:

cat file[25].txt

Bei größeren Zahlen als 9 ist die Klammererweiterung nützlich (siehe jedoch Hinweis unten für den Unterschied zwischen Globbing-Mustern und Klammererweiterungen):

cat file{25..60}.txt

Auch hier ermöglicht die Klammererweiterung einzelne Zahlen:

cat file{12,45,900,xyz}.txt

(Beachten Sie, dass im obigen Beispiel die Klammererweiterung keine arithmetische Schleife beinhaltet, sondern nur Namen basierend auf den bereitgestellten Zeichenfolgen generiert.)

In bash, wenn die extglobShell-Option aktiviert ist ( shopt -s extglob), funktioniert auch Folgendes:

cat file@(12|45|490|foo).txt

Das @(...)Muster |stimmt mit einem der eingeschlossenen begrenzten Muster überein.


Der Unterschied zwischen Globbing-Mustern als [...]und @(...)und Klammererweiterungen besteht darin, dass eine Klammererweiterung in der Befehlszeile generiert wird und möglicherweise nicht mit vorhandenen Namen im aktuellen Verzeichnis übereinstimmt. Ein Dateinamen-Globbing-Muster stimmt mit den Namen überein, aber die Shell beschwert sich nicht, wenn nicht alle möglichen Namen vorhanden sind. Wenn kein übereinstimmender Name vorhanden ist, bleibt das Muster nicht erweitert, es sei denn, auch die nullglobShell-Option ist festgelegt. In diesem Fall wird das Muster entfernt.

Beispiel:

touch file1

ls file[0-9]

Hier wird nur die Dateiliste für file1angezeigt.

Mit ls file{0..9}, lswürde die Suche nach bemängelt nicht file0, file2usw.

Im folgenden Beispiel berührt der erste Befehl nur vorhandene Namen , die dem angegebenen Muster entsprechen, während in der zweiten Zeile Dateien erstellt werden, die noch nicht vorhanden sind:

touch file[0-9]

touch file{0..9}
Kusalananda
quelle
@thecarpy Es tut mir leid, aber das ist kein Muster, das z file45.txt. Der Klammerausdruck [...]funktioniert genauso wie der reguläre Ausdruck, wird jedoch !anstelle von ^"nicht in" verwendet. Ein [...]Muster entspricht immer einem einzelnen Zeichen.
Kusalananda
Sie haben Recht! Übrigens, meine {1,2}ist auch nicht POSIX-konform ... habe heute ein paar neue Dinge gelernt!
Thecarpy
2
Die Tatsache, dass Klammererweiterungen nicht mit echten Dateien übereinstimmen müssen, kann äußerst nützlich sein, wenn Sie sie verwenden, um (zum Beispiel) Muster zu generieren, an die übergeben werden soll grep, URLs zu generieren curl, an die übergeben werden soll ... aber es kann auch verwirrend sein an Menschen, die es gewohnt sind, mit Globs zu arbeiten.
Kevin
@ Kevin Richtig. Bei einer Klammererweiterung muss es sich nicht um Dateinamen handeln.
Kusalananda
7

Die Syntax zur Verwendung ist , file{1,2}die evaluieren file1und file2.

$ ls
$ touch file{1,2,3,4,5,6,7,8,9}
$ ls
file1  file2  file3  file4  file5  file6  file7  file8  file9

Wie Inian auch weiter unten betonte ... wäre es touch file{1..9}in diesem Beispiel einfacher ...

$ ls
$ touch file{1..9}
$ ls
file1  file2  file3  file4  file5  file6  file7  file8  file9

Sie können auch mehrere Ausdrücke verwenden, z.

$ ls
$ touch file{1..9}{a..z}
$ ls
file1a file1b file1c
[...]
file9x file9y file9z

Ja, mit den oben genannten Dateien werden 234 ( 9Mal- 26) Dateien erstellt.

thecarpy
quelle
1
Diese file{1,2} Syntax ist auch praktisch, um Dateien umzubenennen:mv some_very_long_filename.txt{,.bak}
Eric Duminil
6

Ja, Sie können die Klammererweiterung in der bashSchale verwenden. Für nur ein paar Dateien einfach file{1..2}oder genausofile{1,2}

Oder wenn Sie sich Sorgen machen, dass die Dateien in einigen Fällen nicht vorhanden sind, führen Sie einfach eine einfache Schleife durch.

for file in file{1..4}.txt; do
    [ -f "$file" ] || continue
    echo "$file" # Do other actions on file here
done

Oder wenn nur die Verkettung Ihre einzige Operation für die Dateien ist und Sie nicht sicher sind , welche Dateien zu irgendeinem Zeitpunkt nicht vorhanden sein könnten, nur catdiese und unterdrücken Sie die Fehler. Eine Umleitung des Standardfehlers auf /dev/nullwürde die Fehler unterdrücken, wenn die Datei nicht verfügbar ist.

cat file{1,5}.txt 2>/dev/null

oder verwenden Sie den Glob-Ausdruck, file[15]der sich nicht über die Fehler beschwert, wenn die Datei nicht gefunden wurde.

cat file[15].txt
Inian
quelle
2
Nein, keine Bedenken, dass Dateien nicht vorhanden sind. Ich wollte nur den Inhalt von 2 numerisch nummerierten Dateien anzeigen, die jedoch nicht fortlaufend sind. Daher fehlte mir lediglich die Kommasyntax file{1,5}!
Joe Healey