it-swarm.com.ru

Как вы запускаете команду для каждой строки файла?

Например, сейчас я использую следующее, чтобы изменить пару файлов, чьи пути Unix я записал в файл:

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

Есть ли более элегантный, безопасный способ?

112
hawk

Если ваш файл не слишком большой и все файлы имеют с хорошими именами (без пробелов и других специальных символов, таких как кавычки), вы можете просто:

chmod 755 $(<file.txt)

Если у вас есть специальные символы и/или много строк в file.txt.

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

если ваша команда должна быть выполнена ровно 1 раз по записи:

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

Это не нужно для этого примера, так как chmod принимает несколько файлов в качестве аргумента, но это соответствует названию вопроса.

В некоторых особых случаях вы можете даже определить местоположение аргумента файла в командах, сгенерированных xargs:

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

Да.

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

Таким образом, вы можете избежать процесса cat.

cat почти всегда плох для такой цели, как эта. Вы можете прочитать больше о Бесполезное использование Cat.

120
P.P.

Если вы знаете, что у вас нет пробелов на входе:

xargs chmod 755 < file.txt

Если в путях могут быть пробелы и если у вас есть GNU xargs:

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

если у вас есть селектор Nice (например, все .txt файлы в директории) вы можете сделать:

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

удар для петли

или ваш вариант: 

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

Если вы хотите запустить свою команду параллельно для каждой строки, вы можете использовать GNU Параллельно

parallel -a <your file> <program>

Каждая строка вашего файла будет передана программе в качестве аргумента. По умолчанию parallel запускает столько потоков, сколько считает ваш ЦП. Но вы можете указать это с -j

10
janisz

Я вижу, что вы пометили bash, но Perl также был бы хорошим способом сделать это:

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

Вы также можете применить регулярное выражение, чтобы убедиться, что вы получаете нужные файлы, например, обрабатывать только .txt файлы:

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

Чтобы «просмотреть» происходящее, просто замените галочки на двойные кавычки и добавьте print:

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

Вы также можете использовать AWK, что даст вам больше возможностей для обработки файла.

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

если ваш файл имеет разделитель полей, например:

field1, field2, field3

Чтобы получить только первое поле, которое вы делаете

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

Вы можете проверить более подробную информацию в GNU Documentation https://www.gnu.org/software/gawk/manual/html_node/Very-Simple.html#Very-Simple

0
brunocrt

Логика относится ко многим другим целям. А как прочитать .sh_history каждого пользователя из/home/filesystem? Что если их будет тысяча?

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

Вот сценарий https://github.com/imvieira/SysAdmin_DevOps_Scripts/blob/master/get_and_run.sh

0
igor.monteiro