wake-up-neo.net

Wie führen Sie einen Befehl für jede Zeile einer Datei aus?

Zum Beispiel verwende ich jetzt zum Ändern einiger Dateien, deren Unix-Pfade ich in eine Datei geschrieben habe:

cat file.txt | while read in; do chmod 755 "$in"; done

Gibt es einen eleganteren, sichereren Weg?

112
hawk

Wenn Ihre Datei nicht zu groß ist und alle Dateien gut benannt sind (ohne Leerzeichen oder andere Sonderzeichen wie Anführungszeichen), können Sie einfach Folgendes tun:

chmod 755 $(<file.txt)

Wenn Sie spezielle Zeichen und/oder viele Zeilen in file.txt haben.

xargs -0 chmod 755 < <(tr \\n \\0 <file.txt)

wenn Ihr Befehl genau 1 Mal nach Eingabe ausgeführt werden muss:

xargs -0 -n 1 chmod 755 < <(tr \\n \\0 <file.txt)

Dies ist für dieses Beispiel nicht erforderlich, da chmod mehrere Dateien als Argument akzeptiert, dies entspricht jedoch dem Titel der Frage.

Für einen Sonderfall können Sie sogar den Ort des Dateiarguments in Befehlen definieren, die von xargs generiert werden:

xargs -0 -I '{}' -n 1 myWrapper -arg1 -file='{}' wrapCmd < <(tr \\n \\0 <file.txt)
79
F. Hauri

Ja.

while read in; do chmod 755 "$in"; done < file.txt

Auf diese Weise können Sie einen cat-Prozess vermeiden.

cat ist für einen solchen Zweck fast immer schlecht. Sie können mehr über Unbrauchbare Verwendung von Cat erfahren.

120
P.P.

Wenn Sie wissen, dass Sie keine Leerzeichen in der Eingabe haben:

xargs chmod 755 < file.txt

Wenn in den Pfaden Whitespace vorhanden sein könnte und Sie GNU xargs haben:

tr '\n' '\0' < file.txt | xargs -0 chmod 755
13
glenn jackman

wenn Sie einen Nice-Selektor haben (zum Beispiel alle TXT-Dateien in einem Verzeichnis) könnten Sie Folgendes tun:

for i in *.txt; do chmod 755 "$i"; done

bash für Schleife

oder eine Variante von dir: 

while read line; do chmod 755 "$line"; done <file.txt
11
d.raev

Wenn Sie Ihren Befehl für jede Zeile parallel ausführen möchten, können Sie GNU Parallel verwenden.

parallel -a <your file> <program>

Jede Zeile Ihrer Datei wird als Argument an das Programm übergeben. Standardmäßig führt parallel so viele Threads aus, wie Ihre CPUs zählen. Sie können es aber mit -j angeben.

10
janisz

Ich sehe, dass Sie bash getaggt haben, aber Perl wäre auch eine gute Möglichkeit, dies zu tun:

Perl -p -e '`chmod 755 $_`' file.txt

Sie können auch einen Regex anwenden, um sicherzustellen, dass Sie die richtigen Dateien erhalten, z. Nur TXT-Dateien verarbeiten:

Perl -p -e 'if(/\.txt$/) `chmod 755 $_`' file.txt

Um "Vorschau" zu erhalten, ersetzen Sie einfach die Backticks durch doppelte Anführungszeichen und setzen Sie print voran:

Perl -p -e 'if(/\.txt$/) print "chmod 755 $_"' file.txt
2
1.618

Sie können auch AWK verwenden, um die Datei flexibler zu gestalten

awk '{ print "chmod 755 "$0"" | "/bin/sh"}' file.txt

wenn Ihre Datei ein Feldtrennzeichen enthält:

feld1, Feld2, Feld3

Um nur das erste Feld zu erhalten, das Sie tun

awk -F, '{ print "chmod 755 "$1"" | "/bin/sh"}' file.txt

Weitere Informationen finden Sie in der GNU -Dokumentation https://www.gnu.org/software/gawk/manual/html_node/Very-Simple.html#Very-Simple

0
brunocrt

Die Logik gilt für viele andere Ziele. Und wie liest man .sh_history von jedem Benutzer aus/home/filesystem? Was ist, wenn es Tausende von ihnen gibt?

#!/bin/ksh
last |head -10|awk '{print $1}'|
 while IFS= read -r line
 do
su - "$line" -c 'tail .sh_history'
 done

Hier ist das Skript https://github.com/imvieira/SysAdmin_DevOps_Scripts/blob/master/get_and_run.sh

0
igor.monteiro