Никогда, никогда не используйтеfor foo in $(cat bar)
. Это классическая ошибка, обычно известная как ловушка bash № 1 . Вместо этого вы должны использовать:
while IFS= read -r file; do mv -- "$file" "new_place/$file"; done < file_list.txt
При запуске for
цикла, баш будет применяться wordsplitting к тому , что он читает, а это означает , что a strange blue cloud
будет читать a
, strange
, blue
и cloud
:
$ cat files
a strange blue cloud.txt
$ for file in $(cat files); do echo "$file"; done
a
strange
blue
cloud.txt
По сравнению с:
$ while IFS= read -r file; do echo "$file"; done < files
a strange blue cloud.txt
Или даже, если вы настаиваете на UUoC :
$ cat files | while IFS= read -r file; do echo "$file"; done
a strange blue cloud.txt
Таким образом, while
цикл будет считывать входные данные и использовать их read
для назначения каждой строки переменной. В IFS=
устанавливает поле ввода разделитель NULL * , а также -r
вариант из read
останавливает его от интерпретации обратный слеш (так , что \t
рассматривается как слэш + , t
а не в качестве вкладки). Значение --
после mv
означает «обрабатывать все после - как аргумент, а не как параметр», что позволяет вам иметь дело с именами файлов, начинающимися с -
корректно.
* Здесь нет необходимости, строго говоря, единственное преимущество в этом сценарии заключается в том, что он удерживает read
от удаления любых начальных или конечных пробелов, но это хорошая привычка, когда вам нужно иметь дело с именами файлов, содержащими символы новой строки, или в общем, когда вам нужно иметь возможность иметь дело с произвольными именами файлов.
IFS=
не поможет с переводом строк в именах файлов. Формат файла здесь просто не допускает имен файлов с символами новой строки.IFS=
необходим для имен файлов, начинающихся с пробела или табуляции (или любых других символов, кроме новой строки $ IFS, содержащейся ранее).ls
илиfind
с подстановками команд, когда есть лучшие, более надежные способы сделать это.$(cat file)
было бы хорошо, когда все сделано правильно. С «циклом чтения» так же трудно «сделать все правильно», как и с циклом for + $ (...). Смотри мой ответ.То, что
$(cat file_list.txt)
в оболочках POSIX, какbash
в контексте списка, является оператором split + glob (zsh
только делит часть, как вы ожидаете).Он разделяется на символы
$IFS
(по умолчанию SPC , TAB и NL) и выполняет глобирование, если вы не отключите глобализацию полностью.Здесь вы хотите разделить только на новую строку и не хотите глобальную часть, так и должно быть:
Это также имеет преимущество (по сравнению с
while read
циклом), чтобы отбросить пустые строки, сохранить конечную неопределенную строку и сохранитьmv
ввод (необходим, например, в случае подсказок).Недостатком является то, что полное содержимое файла должно храниться в памяти (несколько раз с такими оболочками, как
bash
иzsh
).С некоторыми оболочек (
ksh
,zsh
и в меньшей степениbash
), вы можете оптимизировать его$(<file_list.txt)
вместо$(cat file_list.txt)
.Чтобы сделать эквивалент с
while read
циклом, вам нужно:Или с
bash
:Или с
zsh
:Или с GNU
mv
иzsh
:Или с GNU
mv
и GNUxargs
и ksh / zsh / bash:Подробнее о том, что значит оставлять расширения без кавычек, о последствиях для безопасности, связанных с забыванием заключать в кавычки переменную в оболочках bash / POSIX
источник
$(cat file_list.txt)
считывает весь файл в память перед итерацией, тогда какwhile read ...
читает только одну строку за раз. Это может быть проблемой для больших файлов.Вместо написания скрипта вы можете использовать find ..
для случая, когда файлы находятся в файле, вы можете сделать следующее:
второй не уверен, хотя ..
Удачи
источник
find
, вы можете также использоватьfind
для всего. Зачем вноситьxargs
в это?find -type f -iname '*.txt' -exec mv {} /folder/to/destination/
,-exec
отлично работает с произвольными именами файлов (включая те, которые содержат пробелы, переводы строки или любые другие странности). Я знаю, какxargs
работает, спасибо :) Я просто не вижу смысла в вызове отдельной команды, когда онаfind
уже может сделать это для вас. В этом нет ничего плохого, просто неэффективно.xargs
также имеет недостаток в залипании стандартного ввода (котороеmv
необходимо для его подсказок). Также проблема с решением @ terdon. С GNUxargs
и оболочками с заменой процесса можно смягчить с помощьюxargs -0IF -a <(find...) mv F /dest
#! / Bin / Баш
FILE =
zenity --title "Pick a Movie" --file-selection
для ФАЙЛА в "$ {FILE [0]}"
do omxplayer "$ {FILE [0]}" готово
! / Bin / Баш
FILE =
zenity --title "Pick a Song" --file-selection
для ФАЙЛА в "$ {FILE [0]}"
проиграть "$ {FILE [0]}"
! / Bin / Баш
DIR =
zenity --title "Pick a Album" --file-selection --directory
для DIR в "$ {DIR [0]}"
сделать CD "$ {DIR [0]}" && найти. -тип f -name ' .ogg' -o -name ' .mp3' | sort --version-sort | пока читаешь DIR; играть "$ DIR" готово
! / Bin / Баш
DIR =
zenity --title "Pick a Album" --file-selection --directory
для DIR в "$ {DIR [0]}"
сделать CD "$ {DIR [0]}" && найти. -тип f -name ' .ogg' -o -name ' .mp3' | пока читаешь DIR; играть "$ DIR" готово
источник