Ответ 1
Читайте файл построчно и выполняйте команды: 4 ответа
Это потому, что есть не только 1 ответ...
shell
расширение командной строкиxargs
специальный инструментwhile read
с некоторыми замечаниямиwhile read -u
с использованием выделенногоfd
для интерактивной обработки (пример)
Что касается запроса OP: запуск chmod
для всех целей, перечисленных в файле, xargs
является указанным инструментом. Но для некоторых других приложений небольшое количество файлов и т.д....
Читать весь файл как аргумент командной строки.
Если ваш файл не слишком большой и все файлы имеют правильные имена (без пробелов и других специальных символов, таких как кавычки), вы можете использовать расширение командной строки
shell
. Просто:chmod 755 $(<file.txt)
Для небольшого количества файлов (строк) эта команда является более легкой.
xargs
- правильный инструментДля большего количества файлов или почти для любого количества строк во входном файле...
Для многих инструментов binutils, таких как
chown
,chmod
,rm
,cp -t
...xargs 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)
Тест с
seq 1 5
в качестве вводаПопробуйте это:
xargs -n 1 -I{} echo Blah {} blabla {}.. < <(seq 1 5) Blah 1 blabla 1.. Blah 2 blabla 2.. Blah 3 blabla 3.. Blah 4 blabla 4.. Blah 5 blabla 5..
Где командование выполняется один раз в строке.
while read
и варианты.Как предполагает OP,
cat file.txt | while read in; do chmod 755 "$in"; done
будет работать, но есть 2 проблемы:cat |
- бесполезная вилка, и| while ... ;done
станет недоработкой, и после;done
среда исчезнет.
Так что это может быть лучше написано:
while read in; do chmod 755 "$in"; done < file.txt
Но,
Вас могут предупредить о флагах
$IFS
иread
:help read
read: read [-r] ... [-d delim] ... [name ...] ... Reads a single line from the standard input... The line is split into fields as with word splitting, and the first word is assigned to the first NAME, the second word to the second NAME, and so on... Only the characters found in $IFS are recognized as word delimiters. ... Options: ... -d delim continue until the first character of DELIM is read, rather than newline ... -r do not allow backslashes to escape any characters ... Exit Status: The return code is zero, unless end-of-file is encountered...
В некоторых случаях вам может понадобиться использовать
while IFS= read -r in;do chmod 755 "$in";done <file.txt
Для избежания проблем с чужими именами файлов. И, может быть, если у вас возникнут проблемы с
UTF-8
:while LANG=C IFS= read -r in ; do chmod 755 "$in";done <file.txt
Пока вы используете
STDIN
для чтенияfile.txt
, ваш сценарий не может быть интерактивным (вы больше не можете использоватьSTDIN
).
while read -u
, используя выделенныйfd
.Синтаксис:
while read ...;done <file.txt
перенаправитSTDIN
вfile.txt
. Это означает, что вы не сможете иметь дело с процессом, пока он не закончится.Если вы планируете создать интерактивный инструмент, вам следует избегать использования
STDIN
и использовать какой-либо альтернативный дескриптор файла.Дескрипторы файла констант:
0
для STDIN,1
для STDOUT и2
для STDERR. Вы можете увидеть их по:ls -l /dev/fd/
или
ls -l /proc/self/fd/
Оттуда вы должны выбрать неиспользуемый номер между
0
и63
(на самом деле больше, в зависимости от инструмента суперпользователяsysctl
) в качестве дескриптора файла:Для этой демонстрации я буду использовать fd
7
:exec 7<file.txt # Without spaces between '7' and '<'! ls -l /dev/fd/
Тогда вы можете использовать
read -u 7
следующим образом:while read -u 7 filename;do ans=;while [ -z "$ans" ];do read -p "Process file '$filename' (y/n)? " -sn1 foo [ "$foo" ]&& [ -z "${foo/[yn]}" ]&& ans=$foo || echo '??' done if [ "$ans" = "y" ] ;then echo Yes echo "Processing '$filename'." else echo No fi done
Чтобы закрыть
fd/7
:exec 7<&- # This will close file descriptor 7. ls -l /dev/fd/