it-swarm.com.de

Lassen Sie xargs den Befehl einmal für jede Eingabezeile ausführen

Wie kann ich xargs veranlassen, dass der Befehl für jede eingegebene Zeile genau einmal ausgeführt wird? Das Standardverhalten besteht darin, die Zeilen zu bündeln und den Befehl einmal auszuführen, wobei jeder Instanz mehrere Zeilen übergeben werden. 

Von http://en.wikipedia.org/wiki/Xargs

find/path -type f -print0 | xargs -0 rm

In diesem Beispiel liefert find die Eingabe von xargs mit einer langen Liste von Dateinamen. xargs teilt diese Liste dann in Unterlisten auf und ruft rm einmal für jede Unterliste auf. Dies ist effizienter als diese funktional äquivalente Version:

find/path -type f -exec rm '{}' \;

Ich weiß, dass find das Flag "exec" hat. Ich zitiere nur ein anschauliches Beispiel aus einer anderen Quelle.

278
Readonly

Folgendes funktioniert nur, wenn Ihre Eingabe keine Leerzeichen enthält:

xargs -L 1
xargs --max-lines=1 # synonym for the -L option

von der Manpage:

-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.
344
Draemon

Es scheint mir, dass alle auf dieser Seite vorhandenen Antworten falsch sind, einschließlich der als richtig markierten. Das liegt daran, dass die Frage mehrdeutig formuliert ist.

Zusammenfassung: Wenn Sie den Befehl "genau einmal für jede angegebene Eingabezeile" ausführen möchten, indem Sie die gesamte Zeile (ohne Newline) an den Befehl als einzelnes Argument übergeben, dann ist dies der beste UNIX-kompatible Weg, dies zu tun:

... | tr '\n' '\0' | xargs -0 -n1 ...

GNU xargs verfügt möglicherweise über nützliche Erweiterungen, mit denen Sie tr abschaffen können. Sie sind jedoch unter OS X und anderen UNIX-Systemen nicht verfügbar.

Nun zur langen Erklärung…


Bei der Verwendung von xargs sind zwei Punkte zu berücksichtigen:

  1. wie wird die Eingabe in "Argumente" aufgeteilt? und
  2. wie viele Argumente gleichzeitig den untergeordneten Befehl übergeben.

Um das Verhalten von xargs zu testen, benötigen wir ein Dienstprogramm, das anzeigt, wie oft es ausgeführt wird und mit wie vielen Argumenten. Ich weiß nicht, ob es ein Standardprogramm dafür gibt, aber wir können es leicht in bash programmieren:

#!/bin/bash
echo -n "-> "; for a in "[email protected]"; do echo -n "\"$a\" "; done; echo

Angenommen, Sie speichern es als show in Ihrem aktuellen Verzeichnis und machen es ausführbar, so funktioniert es:

$ ./show one two 'three and four'
-> "one" "two" "three and four" 

Wenn es sich bei der ursprünglichen Frage wirklich um Punkt 2 handelt (wie ich denke, nachdem ich sie ein paar Mal gelesen habe), und so ist sie zu lesen (Änderungen in Fettschrift):

Wie kann ich xargs den Befehl genau einmal für jedes Argument der eingegebenen Eingabe ausführen lassen? Das Standardverhalten besteht darin, Eingabe in Argumente zu unterteilen und den Befehl so oft wie möglich auszuführen, wobei an jede Instanz mehrere Argumente übergeben werden.

dann lautet die Antwort -n 1

Vergleichen wir das Standardverhalten von xargs, das die Eingabe um Leerzeichen aufteilt und den Befehl so oft wie möglich aufruft:

$ 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 sich die ursprüngliche Frage dagegen um Punkt 1 handelte, war die Aufteilung der Eingabedateien so zu lesen (viele Leute, die hierher kommen, scheinen zu glauben, dass dies der Fall ist oder die beiden Fragen verwirrt):

Wie kann ich xargs veranlassen, dass der Befehl with genau ein Argument für jede angegebene Eingabezeile ausgeführt wird? Standardmäßig werden die Zeilen um Leerzeichen aufgeteilt.

dann ist die Antwort subtiler.

Man könnte denken, dass -L 1 hilfreich sein könnte, aber es stellt sich heraus, dass das Argument-Parsing nicht geändert wird. Er führt den Befehl nur einmal für jede Eingabezeile aus, mit so vielen Argumenten, wie in dieser Eingabezeile vorhanden waren:

$ 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, wird sie an die nächste angehängt:

$ echo $'one \ntwo\nthree and four' | xargs -L 1 ./show 
-> "one" "two" 
-> "three" "and" "four" 

Natürlich geht es bei -L nicht darum, wie xargs die Eingabe in Argumente aufteilt.

Das einzige Argument, das plattformübergreifend ist (mit Ausnahme der Erweiterungen GNU), ist -0, das die Eingabe in NUL-Bytes aufteilt.

Dann müssen Sie nur Zeilenumbrüche mit Hilfe von tr in NUL übersetzen:

$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show 
-> "one " "two" "three and four" 

Nun sieht das Argument Parsen gut aus, einschließlich des nachgestellten Leerraums.

Wenn Sie diese Technik mit -n 1 kombinieren, erhalten Sie genau eine Befehlsausführung pro Eingabezeile, unabhängig von Ihrer Eingabe. Dies ist möglicherweise eine andere Möglichkeit, die ursprüngliche Frage zu betrachten (möglicherweise die intuitivste unter Berücksichtigung des Titels):

$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show 
-> "one " 
-> "two" 
-> "three and four" 
151
Tobia

Wenn Sie den Befehl für die Zeile every (d. H. Ergebnis) ausführen möchten, die von find stammt, wozu brauchen Sie die xargs?

Versuchen:

findPfad-type f -execIhr-Befehl{} \;

wobei das Literal {} durch den Dateinamen ersetzt wird und das Literal \; für find benötigt wird, um zu wissen, dass der benutzerdefinierte Befehl dort endet.

BEARBEITEN:

(Nach der Bearbeitung Ihrer Frage klären Sie, dass Sie -exec wissen)

Von man xargs:

-L max-lines
Verwenden Sie höchstens max-lines nicht leere Eingabezeilen pro Befehlszeile. Nachlaufen Leerzeichen bewirken, dass eine Eingabezeile in der nächsten Eingabezeile logisch fortgesetzt wird . Impliziert -x.

Beachten Sie, dass Dateinamen, die in Leerzeichen enden, Probleme verursachen, 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

Wenn Sie sich also nicht für die -exec-Option interessieren, verwenden Sie -print0 und -0 besser:

$ find . -type f -print0 | xargs -0L1 wc -l
0 ./c
0 ./c
0 ./b
0 ./a
22
tzot

Wie kann ich xargs veranlassen, dass der Befehl für jede angegebene Eingabezeile genau einmal ausgeführt wird?

Ich verwende -L 1 answer nicht, da es keine Dateien mit Leerzeichen verarbeitet, was 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 die Verwendung von tr zum Konvertieren von Zeilenumbrüchen in Nullzeichen (\0) und das Argument xargs -0.

echo "file with space.txt" | tr '\n' '\0' | xargs -0 ls
file with space.txt

Wenn Sie die Anzahl der Aufrufe begrenzen müssen, können Sie das Argument -n 1 verwenden, um für jede Eingabe einen Aufruf an das Programm zu tätigen:

echo "file with space.txt" | tr '\n' '\0' | xargs -0 -n 1 ls

Dadurch können Sie auch die Ausgabe von find before umwandeln, um die Unterbrechungen in Nullen umzuwandeln.

find . -name \*.xml | grep -v /workspace/ | tr '\n' '\0' | xargs -0 tar -cf xml.tar
12
Gray

Eine andere Alternative ...

find /path -type f | while read ln; do echo "processing $ln"; done
9
Richard

Diese beiden Möglichkeiten funktionieren auch und funktionieren auch für andere Befehle, die find nicht verwenden!

xargs -I '{}' rm '{}'
xargs -i rm '{}'

beispiel Anwendungsfall:

find . -name "*.pyc" | xargs -i rm '{}

löscht alle pyc-Dateien in diesem Verzeichnis, auch wenn die pyc-Dateien Leerzeichen enthalten.

4
Alex Riedler
find path -type f | xargs -L1 command 

ist alles, was du brauchst.

4
Nic Ferrier

Der folgende Befehl sucht alle Dateien (-type f) in /path und kopiert sie dann mit cp in den aktuellen Ordner. Beachten Sie die Verwendung von if -I %, um ein Platzhalterzeichen in der cp-Befehlszeile anzugeben, damit nach dem Dateinamen Argumente eingefügt werden können.

find /path -type f -print0 | xargs -0 -I % cp % .

Getestet mit xargs (GNU findutils) 4.4.0

3
Gerry Shaw

Sie können die Anzahl der Zeilen oder Argumente (wenn zwischen den einzelnen Argumenten Leerzeichen stehen) begrenzen, indem Sie die Flags --max-lines bzw. --max-args verwenden.

  -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.
1
Readonly

Die Antworten von @Draemon scheinen mit "-0" richtig zu sein, auch wenn in der Datei Speicherplatz vorhanden ist.

Ich habe den Befehl xargs ausprobiert und habe festgestellt, dass "-0" perfekt mit "-L" funktioniert. Sogar die Leerzeichen werden behandelt (wenn die Eingabe mit Null beendet wurde). Folgendes ist ein Beispiel:

#touch "file with space"
#touch "file1"
#touch "file2"

Im Folgenden werden die Nullen aufgeteilt und der Befehl für jedes Argument in der Liste ausgeführt:

 #find . -name 'file*' -print0 | xargs -0 -L1
./file with space
./file1
./file2

-L1 führt also das Argument für jedes mit Null abgeschlossene Zeichen aus, wenn es mit "-0" verwendet wird. Um den Unterschied zu sehen, versuchen Sie:

 #find . -name 'file*' -print0 | xargs -0 | xargs -L1
 ./file with space ./file1 ./file2

selbst das wird einmal ausgeführt:

 #find . -name 'file*' -print0  | xargs -0  | xargs -0 -L1
./file with space ./file1 ./file2

Der Befehl wird einmal ausgeführt, da das "-L" jetzt nicht auf null Byte aufgeteilt wird. Sie müssen "-0" und "-L" angeben, um zu funktionieren. 

0
Mohammad Karmi

Es scheint, dass ich nicht genug Ruf habe, um einen Kommentar zu Tobias Antwort oben hinzuzufügen. Daher füge ich diese "Antwort" hinzu, um denjenigen von uns zu helfen, die auf den Windows-Plattformen auf die gleiche Weise mit xargs experimentieren möchten.

Hier ist eine Windows-Batchdatei, die dasselbe wie das schnell codierte "show" -Skript von Tobia ausführt:

@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.
0
CrashNeb