Dans $(cat file_list.txt)
les shells POSIX comme bash
dans le contexte de la liste, l'opérateur split + glob ( zsh
ne 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 read
boucle) de supprimer les lignes vides, de conserver une ligne non terminée et de conserver mv
le 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 bash
et zsh
).
Avec certains shells ( ksh
, zsh
et 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 read
boucle, 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 mv
et zsh
:
mv -t -- new_place ${(f)"$(<file_list.txt)"}
Ou avec GNU mv
et GNU xargs
et 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