Ich habe mich mit der Befehlszeile befasst und gelernt, dass |
(Pipeline) die Ausgabe eines Befehls auf die Eingabe eines anderen Befehls umleiten soll. Warum funktioniert der Befehl ls | file
also nicht?
file
input ist einer von mehreren Dateinamen wie file filename1 filename2
ls
Die Ausgabe ist eine Liste der Verzeichnisse und Dateien in einem Ordner, daher ls | file
sollte der Dateityp jeder Datei in einem Ordner angezeigt werden.
Wenn ich es jedoch benutze, ist die Ausgabe:
Usage: file [-bcEhikLlNnprsvz0] [--apple] [--mime-encoding] [--mime-type]
[-e testname] [-F separator] [-f namefile] [-m magicfiles] file ...
file -C [-m magicfiles]
file [--help]
Da gab es einen Fehler bei der Verwendung des file
Befehls
command-line
ls
pipe
file-command
IanC
quelle
quelle
ls
, bedeutet dies, dass alle Dateien im aktuellen Verzeichnis mit demfile
Befehl verarbeitet werden sollen. ... Warum also nicht einfach machenfile *
:, das mit einer Zeile für jede Datei, Ordner antwortet.file *
ist der klügste Weg, ich habe mich nur gefragt, warum diels
Ausgabe nicht funktioniert. Zweifel beseitigt :)ls
ist in der Regel eine schlechte Idee.Antworten:
Das grundlegende Problem besteht darin,
file
dass Dateinamen als Befehlszeilenargumente und nicht als stdin erwartet werden. Beim Schreiben wirdls | file
die Ausgabe vonls
als Eingabe an übergebenfile
. Nicht als Argumente, als Eingabe.Was ist der Unterschied?
Befehlszeilenargumente sind, wenn Sie Flags und Dateinamen nach einem Befehl schreiben, wie in
cmd arg1 arg2 arg3
. In Shell - Skripten sind diese Argumente als die Variablen$1
,$2
,$3
usw. C Sie sie über den Zugriff hattechar **argv
undint argc
Argumentemain()
.Die Standardeingabe stdin ist ein Datenstrom. Einige Programme mögen
cat
oderwc
lesen von stdin, wenn ihnen keine Befehlszeilenargumente gegeben werden. In einem Shell-Skript können Sieread
eine einzelne Eingabezeile abrufen. In C können Sie verwenden ,scanf()
odergetchar()
, unter den verschiedenen Optionen.file
liest normalerweise nicht von stdin. Es wird erwartet, dass mindestens ein Dateiname als Argument übergeben wird. Aus diesem Grund wird die Verwendung beim Schreiben ausgedrucktls | file
, weil Sie kein Argument übergeben haben.Sie können
xargs
stdin wie in in Argumente umwandelnls | xargs file
. Dennoch, wie Terdon erwähnt , ist Parsenls
eine schlechte Idee. Der direkteste Weg, dies zu tun, ist einfach:quelle
file
mithilfe von Dateinamen aus der Eingabels | file -f -
. Immer noch eine schlechte Idee.ls
die Ausgabe infile
's stdin. Versuch es.file $(ls)
noch auf andere Weise erwähnen , was auch funktioniert.Weil, wie Sie sagen, der Eingang
file
hat seinen Dateinamen . Die Ausgabe vonls
ist jedoch nur Text. Dass es sich zufällig um eine Liste von Dateinamen handelt, ändert nichts an der Tatsache, dass es sich lediglich um Text handelt und nicht um den Speicherort von Dateien auf der Festplatte.Wenn Sie die Ausgabe auf dem Bildschirm sehen, sehen Sie Text. Ob dieser Text ein Gedicht oder eine Liste von Dateinamen ist, spielt für den Computer keine Rolle. Alles was es weiß ist, dass es Text ist. Aus diesem Grund können Sie die Ausgabe von
ls
an Programme übergeben, die Text als Eingabe verwenden (obwohl Sie dies wirklich, wirklich nicht tun sollten ):Um die Ausgabe eines Befehls zu verwenden, der Dateinamen als Text (z. B.
ls
oderfind
) als Eingabe für einen Befehl auflistet , der Dateinamen akzeptiert, müssen Sie einige Tricks anwenden. Das typische Werkzeug dafür istxargs
:Wie ich bereits sagte, möchten Sie die Ausgabe von nicht wirklich analysieren
ls
. Etwas wiefind
ist besser (das gibt nach jedem Dateinamenprint0
ein\0
statt eines neuen aus und das-0
vonxargs
lässt es mit solchen Eingaben umgehen; dies ist ein Trick, damit Ihre Befehle mit Dateinamen funktionieren, die Zeilenumbrüche enthalten):Welches hat auch seine eigene Art, dies zu tun, ohne überhaupt zu brauchen
xargs
:Schließlich können Sie auch eine Shell-Schleife verwenden. Beachten Sie jedoch, dass dies in den meisten Fällen
xargs
viel schneller und effizienter ist. Beispielsweise:quelle
file
scheint nicht wirklich zu lesen , es sei denn , eine explizite gegeben stdin-
Platzhalter: vergleichenfile foo
,echo foo | file
undecho foo | file -
; Tatsächlich ist dies wahrscheinlich der Grund für die Verwendungsmeldung im OPs-Fall (dh nicht wirklich, weil die Ausgabe vonls
"einfach Text" ist, sondern weil die Argumentlistefile
leer ist)echo foo | file -
dies nichtfile
für die Datei,foo
sondern für den stdin-Stream ausgeführt wird.cat
Ausnahme von stdin ohne-
Ausnahme der angegebenen Dateiargumente, denke ich.Die Ausgabe wird nicht "umgeleitet", sondern die Ausgabe eines Programms wird als Eingabe verwendet, während die Datei keine Eingaben, sondern Dateinamen als Argumente verwendet , die dann getestet werden. Bei Umleitungen werden diese Dateinamen weder als Argumente noch als Piping übergeben , je später Sie dies tun.
Sie können die Dateinamen aus einer Datei mit der
--files-from
Option lesen, wenn Sie eine Datei haben, in der alle Dateien aufgelistet sind, die Sie testen möchten. Andernfalls übergeben Sie einfach die Pfade zu Ihren Dateien als Argumente.quelle
Die akzeptierte Antwort erklärt, warum der Pipe-Befehl nicht sofort funktioniert und mit dem
file *
Befehl eine einfache, direkte Lösung bietet.Ich würde gerne eine andere Alternative vorschlagen, die sich irgendwann als nützlich erweisen könnte. Der Trick ist die Verwendung des Backtick-
(`)
Zeichens. Das Backtick wird hier ausführlich erklärt . Kurz gesagt, es nimmt die Ausgabe des Befehls, der in den Backticks enthalten ist, und ersetzt ihn als Zeichenfolge im verbleibenden Befehl.Nimmt also
find `ls`
die Ausgabe desls
Befehls und ersetzt sie als Argumente für denfind
Befehl. Dies ist länger und komplizierter als die akzeptierte Lösung, aber Varianten davon können in anderen Situationen hilfreich sein.quelle
command
(den Backslash-Code auf meinem Telefon nicht finden) verwenden, um die Ausgabe eines Befehls in der Bash zu erweitern und ihn als Parameter für andere Befehle zu verwenden. Wirklich nützlich, auch wenn die Verwendung in diesem Fall (mit ls ) aufgrund der Sonderzeichen in einigen Dateinamen zu Problemen führen würde.Die Ausgabe von
ls
über eine Pipe ist ein solider Datenblock mit 0x0a, der jede Zeile - dh ein Zeilenvorschubzeichen - trennt, undfile
wird als ein Parameter abgerufen, bei dem erwartet wird, dass mehrere Zeichen gleichzeitig an einem arbeiten.ls
Generieren Sie in der Regel niemals eine Datenquelle für andere Befehle - eines Tages wird sie weitergeleitet ...rm
und Sie haben dann Probleme!Verwenden Sie besser eine Schleife,
for i in *; do file "$i" ; done
die vorhersehbar die gewünschte Ausgabe erzeugt. Die Anführungszeichen stehen bei Dateinamen mit Leerzeichen.quelle
file *
;-)ls
eine sehr, sehr schlechte Idee ist . Nicht nur, weil Sie es möglicherweise an etwas Schädliches weitergeben, wie zum Beispielrm
, was noch wichtiger ist, weil es bei nicht standardmäßigen Dateinamen bricht.rm
Dateinamen von der Standardeingabe? Ich denke nicht. Auch ist in der Regells
eines der wichtigsten Beispiele für eine Datenquelle für die Verwendung von Unix-Pipelines seit Beginn von Unix. Aus diesem Grund wird standardmäßig ein einfacher Dateiname pro Zeile ohne Attribute oder Verzierungen verwendet, wenn es sich bei der Ausgabe um eine Pipe handelt, anders als bei der üblichen Standardformatierung, wenn die Ausgabe das Terminal ist.Wenn Sie eine Pipe zum Feeden
file
verwenden möchten, verwenden Sie die Option, auf-f
die normalerweise ein Dateiname folgt. Sie können jedoch auch einen einzelnen Bindestrich-
zum Lesen von stdin verwendenDer Trick mit dem Bindestrich
-
funktioniert mit vielen Standard-Befehlszeilenprogrammen (obwohl dies--
manchmal der Fall ist ), daher ist es immer einen Versuch wert.Das Tool
xarg
ist viel leistungsfähiger und wird in den meisten Fällen nur benötigt, wenn die Argumentliste zu lang ist ( Details finden Sie in diesem Beitrag ).quelle
--
? Ich habe das noch nie gesehen.--
ist in der Regel der Indikator "Ende der Flags".Es funktioniert mit dem folgenden Befehl
Es wird für mich besser funktionieren
quelle
Dies sollte auch funktionieren:
wie auch hier besprochen: https://unix.stackexchange.com/questions/5778/was ist der Unterschied zwischen Zeug und Zeug?
quelle
$()
Methode ist mit der Backtick-Methode in askubuntu.com/a/795744/158442