Dans $(cat file_list.txt)les shells POSIX comme bashdans le contexte de la liste, l'opérateur split + glob ( zshne fait que la partie split comme vous vous y attendez).
Il se divise en caractères de $IFS(par défaut, SPC , TAB et NL) et ne fait de glob que si vous désactivez complètement la globalisation.
Ici, vous voulez diviser uniquement sur la nouvelle ligne et ne voulez pas la partie glob, donc ça devrait être:
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
Cela a également l'avantage (sur une while readboucle) de supprimer les lignes vides, de conserver une ligne non terminée et de conserver mvle stdin (nécessaire en cas d'invites par exemple).
Il présente cependant l'inconvénient que le contenu complet du fichier doit être stocké en mémoire (plusieurs fois avec des coques comme bashet zsh).
Avec certains shells ( ksh, zshet dans une moindre mesure bash), vous pouvez l'optimiser avec $(<file_list.txt)au lieu de $(cat file_list.txt).
Pour faire l'équivalent avec une while readboucle, il vous faudrait:
while IFS= read <&3 -r file || [ -n "$file" ]; do
{
[ -n "$file" ] || mv -- "$file" "new_place/$file"
} 3<&-
done 3< file_list.txt
Ou avec bash:
readarray -t files < file_list.txt &&
for file in "${files[@]}"
[ -n "$file" ] || mv -- "$file" "new_place/$file"
done
Ou avec zsh:
for file in ${(f)"$(<file_list.txt)"}
mv -- "$file" "new_place/$file"
done
Ou avec GNU mvet zsh:
mv -t -- new_place ${(f)"$(<file_list.txt)"}
Ou avec GNU mvet GNU xargset ksh / zsh / bash:
xargs -rd '\n' -a <(grep . file_list.txt) mv -t -- new_place
Plus d'informations sur ce que signifie laisser des extensions sans guillemets sur les implications de la sécurité d'oublier de citer une variable dans des shells bash / POSIX