Bahwa $(cat file_list.txt)dalam shell POSIX seperti bashdalam konteks daftar adalah operator split + glob ( zshhanya melakukan bagian split seperti yang Anda harapkan).
Itu terbagi pada karakter $IFS(secara default, SPC , TAB dan NL) dan melakukan glob kecuali Anda mematikan globbing sama sekali.
Di sini, Anda ingin membagi hanya pada baris baru dan tidak ingin bagian glob, jadi seharusnya:
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
Itu juga memiliki keuntungan (lebih dari satu while readloop) untuk membuang garis kosong, mempertahankan garis trailing yang tidak ditentukan, dan mempertahankan mvstdin (diperlukan jika diminta misalnya).
Itu memang memiliki kekurangan meskipun isi penuh file harus disimpan dalam memori (beberapa kali dengan kerang seperti bashdan zsh).
Dengan beberapa shell ( ksh, zshdan pada tingkat lebih rendah bash), Anda dapat mengoptimalkannya dengan $(<file_list.txt)alih - alih $(cat file_list.txt).
Untuk melakukan hal yang sama dengan while readloop, Anda perlu:
while IFS= read <&3 -r file || [ -n "$file" ]; do
{
[ -n "$file" ] || mv -- "$file" "new_place/$file"
} 3<&-
done 3< file_list.txt
Atau dengan bash:
readarray -t files < file_list.txt &&
for file in "${files[@]}"
[ -n "$file" ] || mv -- "$file" "new_place/$file"
done
Atau dengan zsh:
for file in ${(f)"$(<file_list.txt)"}
mv -- "$file" "new_place/$file"
done
Atau dengan GNU mvdan zsh:
mv -t -- new_place ${(f)"$(<file_list.txt)"}
Atau dengan GNU mvdan GNU xargsdan ksh / zsh / bash:
xargs -rd '\n' -a <(grep . file_list.txt) mv -t -- new_place
Lebih banyak membaca tentang apa artinya membiarkan ekspansi tidak dikutip di Implikasi keamanan lupa mengutip variabel dalam bash / POSIX shells