То, что $(cat file_list.txt)
в оболочках POSIX, как bash
в контексте списка, является оператором split + glob ( zsh
только делит часть, как вы ожидаете).
Он разделяется на символы $IFS
(по умолчанию SPC , TAB и NL) и выполняет глобирование, если вы не отключите глобализацию полностью.
Здесь вы хотите разделить только на новую строку и не хотите глобальную часть, так и должно быть:
IFS='
' # split on newline only
set -o noglob # disable globbing
for file in $(cat file_list.txt); do # split+glob
mv -- "$file" "new_place/$file"
done
Это также имеет преимущество (по сравнению с while read
циклом), чтобы отбросить пустые строки, сохранить конечную неопределенную строку и сохранитьmv
ввод (необходим, например, в случае подсказок).
Недостатком является то, что полное содержимое файла должно храниться в памяти (несколько раз с такими оболочками, как bash
иzsh
).
С некоторыми оболочек ( ksh
, zsh
и в меньшей степени bash
), вы можете оптимизировать его $(<file_list.txt)
вместо $(cat file_list.txt)
.
Чтобы сделать эквивалент с while read
циклом, вам нужно:
while IFS= read <&3 -r file || [ -n "$file" ]; do
{
[ -n "$file" ] || mv -- "$file" "new_place/$file"
} 3<&-
done 3< file_list.txt
Или с bash
:
readarray -t files < file_list.txt &&
for file in "${files[@]}"
[ -n "$file" ] || mv -- "$file" "new_place/$file"
done
Или с zsh
:
for file in ${(f)"$(<file_list.txt)"}
mv -- "$file" "new_place/$file"
done
Или с GNU mv
и zsh
:
mv -t -- new_place ${(f)"$(<file_list.txt)"}
Или с GNU mv
и GNU xargs
и ksh / zsh / bash:
xargs -rd '\n' -a <(grep . file_list.txt) mv -t -- new_place
Подробнее о том, что значит оставлять расширения без кавычек, о последствиях для безопасности, связанных с забыванием заключать в кавычки переменную в оболочках bash / POSIX