То, что $(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