Wie kann ich zwei Befehle für eine Eingabe ausführen, ohne diese Eingabe zweimal eingeben zu müssen?
Zum Beispiel sagt der Befehl stat viel über eine Datei aus, gibt jedoch nicht ihren Dateityp an:
stat fileName
Der Befehl file gibt an, um welchen Dateityp es sich handelt:
file fileName
Sie können dies auf folgende Weise in einer Zeile ausführen:
stat fileName ; file fileName
Sie müssen den Dateinamen jedoch zweimal eingeben.
Wie können Sie beide Befehle für dieselbe Eingabe ausführen (ohne die Eingabe oder eine Variable der Eingabe zweimal einzugeben)?
Unter Linux weiß ich, wie Ausgaben weitergeleitet werden, aber wie werden Eingaben weitergeleitet?
command-line
Lonniebiz
quelle
quelle
<
(Eingabe von der Datei zur linken Seite) oder|
(Eingabe vom Stream zur rechten Seite) weitergeleitet werden. Es besteht ein Unterschied.yank-last-arg
Befehl (Standard - TastenkürzelMeta-.
oderMeta-_
,Meta
oft der linke seinAlt
Schlüssel) wird den letzten Parameter aus der vorhergehenden Befehlszeile in die aktuellen kopieren. Nach der Ausführung gebenstat fileName
Sie also einfile [Meta-.]
und müssen das nicht nochfileName
einmal eingeben. Ich benutze das immer.<
und>
sind Umleitung , nicht kochend . Eine Pipeline verbindet zwei Prozesse, während die Umleitung einfach stdin / stdout neu zuordnet.Antworten:
Hier ist ein anderer Weg:
Beispiel:
Das funktioniert in
bash
undzsh
. Das funktioniert auch inmksh
unddash
aber nur wenn interaktiv. In AT & T ksh funktioniert dies nur, wenn sich dasfile "$_"
in einer anderen Leitung als diestat
eine befindet.quelle
!$
funktioniert nicht, da er!$
bis zum letzten Wort des letzten Verlaufsereignisses erweitert wird (also von der zuvor eingegebenen Befehlszeile, nicht vom Befehl stat).Hier ist eine hackige Kombination aus Bash Brace Expansion und Eval, die den Trick zu machen scheint
quelle
csh
, nichtbash
.bash
kopierte es vonksh
. Dieser Code funktioniert in allen csh, tcsh, ksh, zsh, fish und bash.eval
? (unter Bezugnahme auf die Top-Kommentare)Mit
zsh
können Sie anonyme Funktionen nutzen:Mit
es
Lambdas:Sie könnten auch tun:
(Wenn Sie das
stat
Erste tun,file
wird die Zugriffszeit aktualisiert).Ja, würde ich:
Dafür sind aber Variablen da.
quelle
{ stat -; file -;} < filename
ist magisch.stat
muss überprüft werden, ob die stdin mit einer Datei verbunden ist und die Dateiattribute gemeldet werden? Vermutlich wird der Zeiger auf stdin nichtfile
stat -
sagtstat
, einfstat()
auf seiner fd 0 zu tun .{ $COMMAND_A -; $COMMAND_B; } < filename
Variante funktioniert im Allgemeinen nicht, wenn $ COMMAND_A tatsächlich eine Eingabe liest. zB{ cat -; cat -; } < filename
wird der Inhalt des Dateinamens nur einmal gedruckt.stat -
wird speziell seit coreutils-8.0 (Okt. 2009) behandelt. In früheren Versionen erhalten Sie eine Fehlermeldung (es sei denn, Sie haben eine Datei-
aus einem früheren Experiment aufgerufen , in diesem Fall erhalten Sie die falschen Ergebnisse ...)stat -f0
stattdessen verwenden.Alle diese Antworten erscheinen mir mehr oder weniger als Skripte. Für eine Lösung, die wirklich kein Scripting erfordert und davon ausgeht, dass Sie an der Tastatur sitzen und in eine Shell tippen, können Sie Folgendes versuchen:
Drücken Sie in bash, zsh und ksh mindestens im vi- und im emacs-Modus die Escape-Taste und dann den Unterstrich, um das letzte Wort der vorherigen Zeile in den Bearbeitungspuffer der aktuellen Zeile einzufügen.
Alternativ können Sie die Verlaufssubstitution verwenden:
In bash werden zsh, csh, tcsh und die meisten anderen Shells
!$
durch das letzte Wort der vorherigen Befehlszeile ersetzt, wenn die aktuelle Befehlszeile analysiert wird.quelle
Esc _
? Können Sie bitte mit der offiziellen Dokumentation verlinken?Die Art und Weise, wie ich dies vernünftigerweise gefunden habe, ist die Verwendung von xargs, es nimmt eine Datei / Pipe und konvertiert deren Inhalt in Programmargumente. Dies kann mit tee kombiniert werden, das einen Stream aufteilt und an zwei oder mehr Programme sendet. In Ihrem Fall benötigen Sie:
Im Gegensatz zu vielen anderen Antworten funktioniert dies unter Linux in bash und den meisten anderen Shells. Ich werde vorschlagen, dass dies ein guter Anwendungsfall für eine Variable ist, aber wenn Sie absolut keinen verwenden können, ist dies der beste Weg, dies nur mit Pipes und einfachen Dienstprogrammen zu tun (vorausgesetzt, Sie haben keine besonders ausgefallene Shell).
Zusätzlich können Sie dies für eine beliebige Anzahl von Programmen tun, indem Sie diese einfach auf die gleiche Weise wie diese beiden nach dem Tee hinzufügen.
BEARBEITEN
Wie in den Kommentaren angedeutet, weist diese Antwort einige Mängel auf. Der erste ist das Potenzial für Interlacing bei der Ausgabe. Dies kann folgendermaßen behoben werden:
Dadurch werden die Befehle der Reihe nach ausgeführt und die Ausgabe wird niemals interlaced.
Das zweite Problem ist die Vermeidung von Prozessersetzungen, die in einigen Shells nicht verfügbar sind. Dies kann durch die Verwendung von tpipe anstelle von tee erreicht werden:
Dies sollte auf fast jede Shell portierbar sein (ich hoffe) und löst die Probleme in der anderen Empfehlung. Ich schreibe jedoch die letzte aus dem Speicher, da auf meinem aktuellen System keine tpipe verfügbar ist.
quelle
ksh
(nicht in den gemeinfreien Varianten)bash
und funktioniertzsh
. Beachten Sie, dassstat
undfile
gleichzeitig ausgeführt werden, sodass möglicherweise die Ausgabe ineinander verschränkt wird (ich nehme an, Sie verwenden| cat
, um die Ausgabepufferung zu erzwingen, um diesen Effekt zu begrenzen?).Diese Antwort ähnelt einigen anderen:
Im Gegensatz zu den anderen Antworten, bei denen das letzte Argument des vorherigen Befehls automatisch wiederholt wird , müssen Sie für dieses Argument Folgendes zählen:
Im Gegensatz zu einigen anderen Antworten sind hierfür keine Anführungszeichen erforderlich:
oder
quelle
Dies ähnelt einigen anderen Antworten, ist jedoch portabler als diese und viel einfacher als diese :
oder
in dem
sh
zugeordnet ist$0
. Obwohl die Eingabe aus drei weiteren Zeichen besteht, ist diese (zweite) Form vorzuziehen, da dies$0
der Name ist, den Sie dem Inline-Skript geben. Es wird zum Beispiel in Fehlermeldungen der Shell für dieses Skript verwendet, zum Beispiel wennfile
oderstat
nicht gefunden oder aus irgendeinem Grund nicht ausgeführt werden kann.Wenn du willst
für eine beliebige Anzahl von Dateien tun
was funktioniert, weil
"$@"
es äquivalent zu ist"$1" "$2" "$3" …
.quelle
$0
ist der Name, den Sie diesem Inline-Skript geben möchten. Es wird beispielsweise in Fehlermeldungen der Shell für dieses Skript verwendet. Zum Beispiel, wennfile
oderstat
nicht gefunden oder aus irgendeinem Grund nicht ausgeführt werden kann. Also, Sie wollen hier etwas Sinnvolles. Wenn Sie nicht begeistert sind, verwenden Sie einfachsh
.Ich denke, Sie stellen eine falsche Frage, zumindest für das, was Sie versuchen, zu tun.
stat
undfile
Befehle nehmen Parameter an, die der Name einer Datei und nicht der Inhalt davon sind. Der Befehl liest später die Datei, die durch den von Ihnen angegebenen Namen gekennzeichnet ist.Eine Pipe sollte zwei Enden haben, von denen eines als Eingabe und eines als Ausgabe verwendet wird. Dies ist sinnvoll, da Sie möglicherweise verschiedene Bearbeitungen mit verschiedenen Werkzeugen ausführen müssen, bis Sie das gewünschte Ergebnis erhalten. Zu sagen, dass Sie wissen, wie man Ausgänge leitet, aber nicht, wie man Eingänge leitet, ist im Prinzip nicht korrekt.
In Ihrem Fall benötigen Sie überhaupt keine Pipe, da Sie die Eingabe in Form eines Dateinamens vornehmen müssen. Und selbst wenn diese Werkzeuge (
stat
undfile
) stdin lesen würden, ist pipe hier wieder nicht relevant, da die Eingabe von keinem der Werkzeuge geändert werden sollte, wenn es zum zweiten kommt.quelle
Dies sollte für alle Dateinamen im aktuellen Verzeichnis funktionieren.
quelle
}
... und beginnen nicht mit-
. Einigeprintf
Implementierungen (zsh, bash, ksh93) haben a%q
. Mitzsh
, das könnte sein:printf 'stat %q; file %1$q\n' ./* | zsh
sed
s///
, aber es geht um den Umfang - und wenn die Leute das in ihre Dateinamen setzen, sollten sie Windows verwenden.*
zwei . Du könntest es genauso gut sagenstat -- *; file -- *
.*
wird erweitert. Die Erweiterung von*
plus den beiden Befehlen für jedes Argument in*
ist die Eingabe. Sehen?printf commands\ %s\;shift *
Es gibt hier ein paar verschiedene Verweise auf "Eingabe", daher werde ich zunächst einige Szenarien vorstellen, um dies zu verstehen. Für Ihre schnelle Antwort auf die Frage in kürzester Form :
Der obige Befehl führt eine Statistik für die Testdatei durch, nimmt das STDOUT (leitet es um) und fügt es in die nächste Sonderfunktion (den <() -Teil) ein und gibt dann die Endergebnisse dessen, was auch immer das war, in eine neue Datei (Ausgabedatei) aus. Die Datei wird aufgerufen und dann mit den eingebauten Bash-Funktionen referenziert (jeweils $ 1 danach, bis Sie einen neuen Befehlssatz beginnen).
Ihre Frage ist großartig und es gibt verschiedene Antworten und Möglichkeiten, dies zu tun, aber es ändert sich tatsächlich mit dem, was Sie speziell tun.
Zum Beispiel können Sie das auch in einer Schleife abspielen, was sehr praktisch ist. Eine gebräuchliche Verwendung in der Pseudocode-Denkweise ist:
Indem Sie das berücksichtigen und dieses Wissen erweitern, können Sie beispielsweise Folgendes erstellen:
Dies führt ein einfaches ls -A in Ihrem aktuellen Verzeichnis aus und teilt dann mit, während jedes Ergebnis von ls -A bis (und hier ist es schwierig!) Grep "thatword" in jedem dieser Ergebnisse durchlaufen und führt nur das vorherige aus printf (in rot), wenn tatsächlich eine Datei mit dem Zusatz "thatword" gefunden wurde. Außerdem werden die Ergebnisse des grep in einer neuen Textdatei protokolliert, files_that_matched_thatword.
Beispielausgabe:
All dies druckte einfach das Ergebnis von ls-A aus, nichts Besonderes. Füge etwas hinzu, damit es diesmal grept:
Führen Sie es jetzt erneut aus:
Vielleicht ist die Antwort anstrengender, als Sie derzeit suchen, aber ich glaube, dass Sie bei zukünftigen Bemühungen viel mehr davon profitieren werden, wenn Sie solche Notizen in der Hand halten.
quelle