Ich habe ein Programm, das Argumente in der folgenden Syntax erwartet:
prog [-f filename | -g filename1 filename2] ...
Jedem Dateinamen muss das -f
Flag vorangestellt werden . Die folgenden Aufrufe sind beispielsweise gültig für prog
:
prog -f a.txt -g b.txt c.txt -f d.txt
prog -g a.txt b.txt -g c.txt d.txt
prog -f a.txt -f b.txt -f c.txt
… Aber die folgenden sind nicht:
prog -f a.txt b.txt
prog -f a.txt -g b.txt
prog a.txt
In meinem Fall interessiert mich nur die -f
Option.
Ich habe viele Dateien in einem Verzeichnis, die alle auf enden .txt
. Sie sehen so aus:
important-files/
├── a.txt
├── b.txt
├── c.txt
├── d.txt
└── filename with spaces.txt
Ich möchte vermeiden, dass jede Datei einzeln aufgelistet werden muss. Normalerweise würde ich dafür einen einfachen Glob verwenden:
$ prog important-files/*.txt
Dies funktioniert jedoch nicht, da der folgende ungültige Aufruf erzeugt wird:
$ prog important-files/a.txt important-files/b.txt important-files/c.txt important-files/d.txt 'important-files/filename with spaces.txt'
… Wenn ich diesen Aufruf wirklich will:
$ prog -f important-files/a.txt -f important-files/b.txt -f important-files/c.txt -f important-files/d.txt -f 'important-files/filename with spaces.txt'
… Da jedem Dateinamen ein Präfix vorangestellt werden muss, -f
um prog
zu verstehen, dass sie nicht so interpretiert werden sollten -g
.
Was ist der kürzeste Weg, um einen Glob zu verwenden und jeder der Dateien, auf die er erweitert wird, ein Flag voranzustellen?
*.txt(P:\\-f:)
*.txt(P:-f:)
in der Tat (Warum sollten Sie dort einen Backslash setzen?).Antworten:
Verwenden
printf
undxargs
unterstützende, nicht durch Trennzeichen getrennte Eingabe:printf
Durchläuft die Formatzeichenfolge über den Argumenten, sodass für jeden Dateinamen in der Erweiterung des Globs gedruckt-f
und der Dateiname durch das Nullzeichen getrennt wird.xargs
liest dies dann und konvertiert es in Argumente fürprog
. Die--
seit einigen Implementierungen benötigtenprintf
Probleme haben mit einem führenden-
in der Formatzeichenfolge. Alternativ-
kann das durch ersetzt werden\055
, was Standard ist.Gleiches Prinzip wie Rakeshs Antwort , jedoch direkt mit der Wildcard-Erweiterung.
quelle
printf ' -f "%s"' important-files/*.txt | xargs prog
?--
, daprintf '-f\0%s\0' important-files/*.txt
gibt der Fehler :bash: printf: -f: invalid option
. Dieprintf -- '-f\0%s\0' important-files/*.txt
Arbeiten.xargs
seine Eingabe verwendet wird, um Argumente an zu übergebenprog
. Wenn jedoch zu viele Argumente vorhanden sind, werden diese aufgeteilt undprog
mehrmals aufgerufen . Haben wir hier die Möglichkeit, die Argumente an der falschen Stelle aufzuteilen, z. B. anzurufenprog -f a.txt -f b.txt ... -f m.txt -f
und dann anzurufenprog n.txt -f o.txt ...
?Versuchen Sie mit Bash:
Beachten Sie, dass dies nicht nur mit Dateinamen funktioniert, die Leerzeichen enthalten, sondern auch mit Dateinamen, die einfache oder doppelte Anführungszeichen oder sogar Zeilenumbrüche enthalten.
Einfache interaktive Verwendung
Definieren Sie für eine einfache interaktive Verwendung eine Funktion:
Diese Funktion kann wie folgt verwendet werden:
Um die Funktionsdefinition dauerhaft zu machen, platzieren Sie sie in Ihrer
~/.bashrc
Datei.quelle
zsh
hat jetzt einP
glob qualifier dafür .Für ältere Versionen können Sie immer verwenden:
$^f
Aktiviert diercexpandparam
Option für die Erweiterung von$f
, wobei Arrays in einem ähnlichen Stil wie dierc
Shell erweitert werden.In
rc
(oderzsh -o rcexpandparam
):Wird erweitert
prog -fa.txt -fb.txt
, ein bisschen als ob Sie in csh (oder anderen Shells, die die Erweiterung von Klammern unterstützen) geschrieben hätten :prog -f{a.txt,b.txt}
.(Beachten Sie,
*.txt(P:-f:)
dass sich der Dateiname von der Option unterscheidet-ffile.txt
, anstatt zwei Argumente zu übergeben-f
file.txt
. Viele Befehle, einschließlich aller Befehle, die die Standard-getopt()
API zum Parsen von Optionen verwenden, unterstützen beide Möglichkeiten, Argumente an Optionen zu übergeben.)fish
erweitert auch Arrays wie folgt:In
bash
können Sie es emulieren mit:Mit
ksh93
:Für
-f
und die entsprechendenfile.txt
s, die als separate Argumente übergeben werden sollen, eine weitere Option beizsh
Verwendung des Array-Zipping-Operators:Sie können dies für Ihre
-g
Option erweitern. Angenommen, es gibt eine gerade Anzahl vontxt
Dateien:Würde
-g
Optionen mit zwei Dateien gleichzeitig übergeben. Ähnlich wie bei:quelle
-f a.txt
statt-f
a.txt
.-fa.txt
wie für die obigen zsh / rc / fish-Ansätze. Anwendungen,getopt()
die es verwenden, behandeln es genauso wie-f
a.txt
, ich kann nichts über die Anwendung des OP sagen (obwohl es unwahrscheinlich ist, dass es verwendet wird,getopt()
wenn es Optionen gibt, die mehr als ein Argument annehmen). Das ist in der Antwort erwähnt.Wie bereits in einem Kommentar erwähnt:
Dies verwendet das Glob-Qualifikationsmerkmal,
P
das jedem Glob-Match ein separates Wort voranstellt. Wie fast alle Glob-Qualifikanten von zsh hat bash nichts Vergleichbares.Wenn Sie die Fertigstellung für möchten
prog
, führen Sie siezsh
interaktiv aus und geben Sie einprog *.txt(P:-f:)
. Wenn Sie zsh zum ersten Mal interaktiv ausführen, werden Sie aufgefordert, eine Konfiguration festzulegen. Wenn Sie sich nicht für zsh interessieren, wählen Sie entweder die Option zum Erstellen eines Leerzeichens.zshrc
(aber Sie werden einige zsh-Funktionen vermissen, die explizit aktiviert werden müssen) oder wählen1
Sie die Menüs aus und gehen Sie sie durch, um die empfohlenen Standardeinstellungen zu aktivieren.quelle
Eins. Methode dazu ist das GNU find / xargs Duo:
quelle
prog
, was sich beispielsweise auf die vom Programm verwendeten relativen Pfade auswirken kann.find important-files …
stattdessen. Dadurch wird auch das von @Kusalananda erwähnte Problem vermieden.POSIXly können Sie immer eine Funktion definieren wie:
quelle
exec
hier benötigt?