Verwenden von Daten, die nicht aus einer Datei, sondern aus einer Pipe in Befehlsoptionen gelesen wurden

18

Per man-Definition erhält dieser Befehl die Eingabe aus einer Datei.

$ command -r FILENAME

Angenommen, es FILENAMEhandelt sich um eine Datei mit einer Liste von Dateinamen, wie sie mit generiert wurde ls > FILENAME.

Wie kann ich stattdessen den Befehl mit dem Ergebnis von lsdirekt füttern ? In meinem Kopf sollte so etwas möglich sein:

$ ls | command -r

Aber es ist nicht der Fall, die Ausgabe von lswird nicht als Argument gehakt. Ausgabe:

Usage: command -r FILENAME
error: -r option requires an argument

Wie kann ich den gewünschten Effekt erzielen?

Paolo
quelle
Weitere Antworten hierzu in einer verwandten Frage: Wie übergebe ich eine Zeichenfolge an einen Befehl, der eine Datei erwartet?
Ilkkachu

Antworten:

31

Dies ist befehlsabhängig. Einige Befehle, die aus einer Datei lesen, gehen davon aus, dass es sich bei der Datei um eine reguläre Datei handelt, deren Größe im Voraus bekannt ist und die von jeder Position gelesen und zurückgespult werden kann. Dies ist unwahrscheinlich, wenn der Inhalt der Datei eine Liste von Dateinamen ist: Dann ist der Befehl wahrscheinlich mit einer Pipe zufrieden , die von Anfang bis Ende nacheinander gelesen wird. Es gibt verschiedene Möglichkeiten, Daten über eine Pipe an einen Befehl weiterzuleiten, der einen Dateinamen erwartet.

  • Viele Befehle werden -als spezielle Namen behandelt, dh sie werden von der Standardeingabe gelesen, anstatt eine Datei zu öffnen. Dies ist eine Konvention, keine Verpflichtung.

    ls | command -r -
  • Viele Unix-Varianten enthalten spezielle Dateien /dev, die die Standarddeskriptoren bezeichnen. Wenn /dev/stdinvorhanden, entspricht das Öffnen und Lesen der Datei dem Lesen der Standardeingabe. Ebenso, /dev/fd/0wenn es existiert.

    ls | command -r /dev/stdin
    ls | command -r /dev/fd/0
  • Wenn Ihre Shell ksh, bash oder zsh ist, können Sie die Shell mit der Zuweisung eines Dateideskriptors beauftragen. Der Hauptvorteil dieser Methode besteht darin, dass sie nicht an die Standardeingabe gebunden ist, sodass Sie die Standardeingabe für etwas anderes verwenden und sie mehrmals verwenden können.

    command -r <(ls)
  • Wenn der Befehl erwartet, dass der Name eine bestimmte Form hat (normalerweise eine bestimmte Erweiterung), können Sie versuchen, ihn mit einem symbolischen Link zu täuschen.

    ln -s /dev/fd/0 list.foo
    ls | command -r list.foo

    Oder Sie können eine Named Pipe verwenden.

    mkfifo list.foo
    ls >list.foo &
    command -r list.foo

Beachten Sie, dass das Generieren einer Liste von Dateien mit lsproblematisch ist, da lsdie Dateinamen in der Regel unleserlich werden, wenn sie nicht druckbare Zeichen enthalten. printf '%s\n' *ist zuverlässiger - es wird jedes Byte buchstäblich in Dateinamen gedruckt. Dateinamen, die Zeilenumbrüche enthalten, verursachen weiterhin Probleme. Dies ist jedoch unvermeidbar, wenn der Befehl eine Liste von Dateinamen erwartet, die durch Zeilenumbrüche getrennt sind.

Gilles 'SO - hör auf böse zu sein'
quelle
+1 für die Aufzählung aller Möglichkeiten. Die IMO-Prozessersetzung ist die richtige Antwort auf diese Situation.
Glenn Jackman
7

Es sollte sein:

ls | xargs -n 1 command -r

Bearbeiten: für Namen mit Leerzeichen:

ls | xargs -d '\n' -n 1 command -r
ghm1014
quelle
Dies kann problematisch sein, wenn commanddavon ausgegangen wird, dass alle für die Befehlszeile erforderlichen Dateinamen gleichzeitig vorhanden sind. Einige Versionen von xargs geben jeweils commandeinige Dateinamen an (10, scheint mir). Sieht aus wie GNU XARGS gibt alles auf einmal.
Bruce Ediger
2

Die einzige zuverlässige Lösung, von der ich weiß, dass sie alle Dateinamen, einschließlich der mit einem Zeilenumbruch, verarbeiten kann, ist:

find . -maxdepth 1 -print0 | xargs -n 1 -0 command -r

Das einzige unzulässige Zeichen im Dateinamen ist in diesem Fall das Nullzeichen, das in Dateinamen ohnehin nicht zulässig ist.

Linus Swälas
quelle
1

Viele Befehle akzeptieren -als "Dateiname", was "Standardeingabe verwenden" bedeutet, aber diese Konvention ist alles andere als universell. Lesen Sie die Manpage.

dmckee
quelle
1

Dies sollte für Ihren Zweck funktionieren: ls | command -r /dev/stdin

Alex
quelle