Machen xargs den Befehl einmal für jede Zeile von Eingangs
-
11-07-2019 - |
Frage
Wie kann ich xargs den Befehl genau einmal ausgeführt für jede Zeile der Eingabe gegeben? Es ist das Standardverhalten zu Brocken ist die Linien und den Befehl einmal ausführen, mehrere Zeilen für jede Instanz übergeben.
http://en.wikipedia.org/wiki/Xargs :
finden / path -type f -print0 | xargs -0 rm
In diesem Beispiel finden speist den Eingang von xargs mit einer langen Liste von Dateinamen. xargs dann teilt diese Liste in Unterlisten und Anrufe rm einmal für jede Unterliste. Das ist effizienter als diese funktional äquivalente Version:
finden / path type f exec rm {} \;
ich weiß, dass die Suche nach dem „exec“ Flag hat. Ich bin nur ein illustratives Beispiel von einer anderen Ressource zu zitieren.
Lösung
Im Folgenden wird nur funktionieren, wenn Sie Räume in Ihrer Eingabe nicht haben:
xargs -L 1
xargs --max-lines=1 # synonym for the -L option
von der man-Seite:
-L max-lines
Use at most max-lines nonblank input lines per command line.
Trailing blanks cause an input line to be logically continued on
the next input line. Implies -x.
Andere Tipps
Es scheint mir, alle bestehenden Antworten auf dieser Seite falsch sind, einschließlich der eine als richtig gekennzeichnet. Das ergibt sich aus der Tatsache, dass die Frage ist mehrdeutig.
Zusammenfassung: Wenn Sie möchten, den Befehl auszuführen „genau einmal für jede Zeile der Eingabe gegeben“ vorbei die gesamte Zeile (ohne Newline) an den Befehl als a Argument, dann ist dies die beste UNIX-kompatible Art und Weise, es zu tun:
... | tr '\n' '\0' | xargs -0 -n1 ...
GNU xargs
kann oder nicht nützliche Erweiterungen, die es Ihnen ermöglichen, mit tr
weg zu tun, aber sie sind auf OS X und anderen UNIX-Systemen verfügbar.
Jetzt für die lange Erklärung ...
Es gibt zwei Probleme zu berücksichtigen, wenn xargs mit:
- Wie funktioniert es die Eingabe in „Argumente“ aufgespalten; und
- , wie viele Argumente des Kind Befehl zu einem Zeitpunkt, zu übergeben.
xargs Verhalten zu testen, brauchen wir ein Programm, das wie oft zeigt sie ausgeführt und mit wie vielen Argumente hat wird. Ich weiß nicht, ob es ein Standard-Dienstprogramm, das zu tun, aber wir können es ganz einfach in der Bash-Code:
#!/bin/bash
echo -n "-> "; for a in "$@"; do echo -n "\"$a\" "; done; echo
Angenommen, Sie es als show
im aktuellen Verzeichnis speichern und ausführbar machen, ist hier, wie es funktioniert:
$ ./show one two 'three and four'
-> "one" "two" "three and four"
Nun, wenn die ursprüngliche Frage ist wirklich über Punkt 2 oben (wie ich denke, es ist, nachdem es ein paar Mal über das Lese) und es ist wie dieses (Änderungen fett) zu lesen:
Wie kann ich xargs den Befehl genau einmal für jedes Argument der Eingabe gegeben ausführen? Sein Standardverhalten ist die Eingabe in Argumente chunk und führen Sie den Befehl so wenig wie möglich , vorbei an mehreren Argumente für jede Instanz.
dann ist die Antwort -n 1
.
Lassen Sie uns xargs' Standardverhalten vergleichen, die die Eingabe um Leerzeichen teilt und ruft den Befehl als wenig wie möglich:
$ echo one two 'three and four' | xargs ./show
-> "one" "two" "three" "and" "four"
und sein Verhalten mit -n 1
:
$ echo one two 'three and four' | xargs -n 1 ./show
-> "one"
-> "two"
-> "three"
-> "and"
-> "four"
Wenn auf der anderen Seite, die ursprüngliche Frage war um Punkt 1. Eingabe Splitting und es war wie folgt gelesen werden (hier viele Leute scheinen kommt der Fall zu denken, das ist, oder verwirrend sind die beiden Punkte):
Wie kann ich den Befehl xargs ausführen mit genau ein Argument für jede Zeile der Eingabe gegeben? Sein Standardverhalten Brocken ist die Zeilen um Leerzeichen .
dann ist die Antwort subtiler.
Man würde denken, dass -L 1
von Hilfe sein könnte, aber es stellt sich heraus, dass es nicht Argument Parsing nicht ändert. Er führt den Befehl nur einmal für jede Eingabezeile, mit so vielen Argumenten wie es gab an diesem Eingabezeile:
$ echo $'one\ntwo\nthree and four' | xargs -L 1 ./show
-> "one"
-> "two"
-> "three" "and" "four"
Nicht nur das, aber wenn eine Zeile mit Leerzeichen endet, es auf die nächste angefügt wird:
$ echo $'one \ntwo\nthree and four' | xargs -L 1 ./show
-> "one" "two"
-> "three" "and" "four"
Natürlich ist -L
nicht über die Art und Weise xargs Änderung der Eingabe in Argumente aufteilt.
Das einzige Argument, das so tut, in einer plattformübergreifenden Art und Weise (ohne GNU-Erweiterungen) ist -0
, die das Eingangs rund NUL Bytes aufteilt.
Dann ist es nur eine Frage der Zeilenumbrüche NUL mit Hilfe von tr
übersetzen:
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show
-> "one " "two" "three and four"
Jetzt das Argument Parsing sieht alles in Ordnung, einschließlich der nachfolgenden Leerzeichen.
Schließlich, wenn Sie diese Technik mit -n 1
kombinieren, erhalten Sie genau eine Befehlsausführung pro Eingabezeile, was Eingang Sie haben, die noch eine andere Art und Weise auf die ursprüngliche Frage zu sehen sein (möglicherweise die intuitive, da der Titel) :
$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show
-> "one "
-> "two"
-> "three and four"
Wenn Sie den Befehl ausführen für alle Linie (d Ergebnis) von find
kommen, was dann brauchen Sie das xargs
für?
Versuchen:
find
Pfad -type f -exec
your-Befehl {} \;
, wo der wörtliche {}
durch den Dateinamen ersetzt wird und die wörtliche \;
für find
muß zu wissen, dass der benutzerdefinierte Befehl endet dort.
EDIT:
(nach dem Bearbeiten Ihrer Frage zu klären, dass Sie über -exec
wissen)
Von man xargs
:
-L max-Linien
Verwenden Sie höchstens max-Linien nicht leere Eingabezeilen pro Kommandozeile. Nachgestellte Rohlinge verursacht eine Eingabezeile auf der nächsten Eingabezeile logisch fortgesetzt werden. Impliziert -x.
Beachten Sie, dass Dateinamen in Rohlingen Endung Sie Probleme verursachen würden, wenn Sie xargs
verwenden:
$ mkdir /tmp/bax; cd /tmp/bax
$ touch a\ b c\ c
$ find . -type f -print | xargs -L1 wc -l
0 ./c
0 ./c
0 total
0 ./b
wc: ./a: No such file or directory
Also, wenn Sie nicht über die -exec
Option ist es egal, Sie besser nutzen -print0
und -0
:
$ find . -type f -print0 | xargs -0L1 wc -l
0 ./c
0 ./c
0 ./b
0 ./a
Wie kann ich xargs den Befehl genau einmal ausgeführt für jede Zeile der Eingabe gegeben?
ich nicht mit -L 1
Antwort, weil es keine Dateien mit Leerzeichen in ihnen umgehen ist, die eine Schlüsselfunktion von find -print0
ist.
echo "file with space.txt" | xargs -L 1 ls
ls: file: No such file or directory
ls: space.txt: No such file or directory
ls: with: No such file or directory
Eine bessere Lösung ist tr
zu verwenden Zeilenumbrüche zu konvertieren Zeichen auf null (\0
) und dann das xargs -0
Argument verwenden.
echo "file with space.txt" | tr '\n' '\0' | xargs -0 ls
file with space.txt
Wenn Sie dann die Anzahl der Anrufe müssen begrenzen Sie das -n 1
Argument verwenden können, einen Aufruf an das Programm für jeden Eingang zu machen:
echo "file with space.txt" | tr '\n' '\0' | xargs -0 -n 1 ls
Dies erlaubt Ihnen auch die Ausgabe der Fund zu filtern vor die Pausen in Nullen umgewandelt wird.
find . -name \*.xml | grep -v /workspace/ | tr '\n' '\0' | xargs -0 tar -cf xml.tar
Eine andere Alternative ...
find /path -type f | while read ln; do echo "processing $ln"; done
find path -type f | xargs -L1 command
ist alles, was Sie brauchen.
Diese beiden Möglichkeiten auch arbeiten, und wird für andere Befehle arbeiten, finden nicht verwenden!
xargs -I '{}' rm '{}'
xargs -i rm '{}'
Beispiel Anwendungsfall:
find . -name "*.pyc" | xargs -i rm '{}
werden alle pyc Dateien in diesem Verzeichnis löschen, auch wenn die pyc Dateien Leerzeichen enthalten.
Mit dem folgenden Befehl werden alle Dateien (Typ f) in /path
finden und dann kopieren Sie sie cp
in den aktuellen Ordner verwenden. Beachten Sie die Verwendung, wenn -I %
ein Platzhalter Zeichen in der cp
Befehlszeile angeben, so dass Argumente nach dem Dateinamen platziert werden.
find /path -type f -print0 | xargs -0 -I % cp % .
Getestet mit xargs (GNU findutils) 4.4.0
Sie können die Zeilenzahl begrenzen, oder Argumente (wenn es Räume zwischen den einzelnen Argumente sind) unter Verwendung der --max-Linien oder --max-args Flaggen sind.
-L max-lines Use at most max-lines nonblank input lines per command line. Trailing blanks cause an input line to be logically continued on the next input line. Implies -x. --max-lines[=max-lines], -l[max-lines] Synonym for the -L option. Unlike -L, the max-lines argument is optional. If max-args is not specified, it defaults to one. The -l option is deprecated since the POSIX standard specifies -L instead. --max-args=max-args, -n max-args Use at most max-args arguments per command line. Fewer than max-args arguments will be used if the size (see the -s option) is exceeded, unless the -x option is given, in which case xargs will exit.
Es scheint, ich habe nicht genug Ruf haben einen Kommentar hinzufügen href="https://stackoverflow.com/a/28806991/5844631"> Tobia Antwort oben zu xargs der gleichen Art und Weise auf den Windows-Plattformen zu experimentieren.
Hier ist eine Windows-Batch-Datei, die die gleiche Sache wie Tobia schnell eine codierte „show“ Skript tut:
@echo off
REM
REM cool trick of using "set" to echo without new line
REM (from: http://www.psteiner.com/2012/05/windows-batch-echo-without-new-line.html)
REM
if "%~1" == "" (
exit /b
)
<nul set /p=Args: "%~1"
shift
:start
if not "%~1" == "" (
<nul set /p=, "%~1"
shift
goto start
)
echo.
@Draemon Antworten scheint richtig zu sein mit „-0“ sogar mit Platz in der Datei.
Ich habe versucht, die xargs Befehl und ich fand, dass „-0“ arbeitet perfekt mit „-L“. auch sind die Räume behandelt (wenn der Eingang null beendet wurde). Folgendes ist ein Beispiel:
#touch "file with space"
#touch "file1"
#touch "file2"
Im Folgenden werden die NULL-Werte geteilt und den Befehl für jedes Argument in der Liste ausführen:
#find . -name 'file*' -print0 | xargs -0 -L1
./file with space
./file1
./file2
so -L1
wird das Argument auf jeder null beendet Zeichen ausgeführt werden, wenn verwendet mit „-0“. Um zu sehen, den Unterschied Versuch:
#find . -name 'file*' -print0 | xargs -0 | xargs -L1
./file with space ./file1 ./file2
selbst wird dies einmal ausführen:
#find . -name 'file*' -print0 | xargs -0 | xargs -0 -L1
./file with space ./file1 ./file2
Der Befehl wird ausgeführt, sobald als „-L“ aufgeteilt jetzt nicht auf null Byte. Sie müssen beide „-0“ und „L“ schaffen, zu arbeiten.
In Ihrem Beispiel der Punkt, der die Ausgabe von Fund xargs kochend ist, dass das Standardverhalten von -exec Option des Funds ist es, den Befehl einmal für jede gefundene Datei auszuführen. Wenn Sie finden, verwenden, und Sie wollen ihre Standardverhalten, dann ist die Antwort ist einfach -. Nicht xargs verwenden zu beginnen
Ausführen ant Aufgabe Rein alle auf jedem build.xml zu aktuellem oder Unterordner.
find . -name 'build.xml' -exec ant -f {} clean-all \;