Isso $(cat file_list.txt)
nos shells POSIX, como bash
no contexto da lista, é o operador split + glob ( zsh
apenas faz a parte dividida conforme o esperado).
Ele se divide em caracteres de $IFS
(por padrão, SPC , TAB e NL) e fica glob a menos que você desative as globbing por completo.
Aqui, você deseja dividir apenas a nova linha e não a parte glob, portanto deve ser:
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
Isso também tem a vantagem (sobre um while read
loop) de descartar linhas vazias, preservar uma linha não terminada à direita e preservar mv
o stdin (necessário em caso de solicitações, por exemplo).
Ele tem a desvantagem de que todo o conteúdo do arquivo deve ser armazenado na memória (várias vezes com shells como bash
e zsh
).
Com algumas conchas ( ksh
, zsh
e em menor grau bash
), você pode otimizá-lo com em $(<file_list.txt)
vez de $(cat file_list.txt)
.
Para fazer o equivalente com um while read
loop, você precisa:
while IFS= read <&3 -r file || [ -n "$file" ]; do
{
[ -n "$file" ] || mv -- "$file" "new_place/$file"
} 3<&-
done 3< file_list.txt
Ou com bash
:
readarray -t files < file_list.txt &&
for file in "${files[@]}"
[ -n "$file" ] || mv -- "$file" "new_place/$file"
done
Ou com zsh
:
for file in ${(f)"$(<file_list.txt)"}
mv -- "$file" "new_place/$file"
done
Ou com GNU mv
e zsh
:
mv -t -- new_place ${(f)"$(<file_list.txt)"}
Ou com GNU mv
e GNU xargs
e ksh / zsh / bash:
xargs -rd '\n' -a <(grep . file_list.txt) mv -t -- new_place
Mais informações sobre o que significa deixar expansões sem citação em Implicações de segurança de esquecer de citar uma variável em shells bash / POSIX