Isso $(cat file_list.txt)nos shells POSIX, como bashno contexto da lista, é o operador split + glob ( zshapenas 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 readloop) de descartar linhas vazias, preservar uma linha não terminada à direita e preservar mvo 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 bashe zsh).
Com algumas conchas ( ksh, zshe 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 readloop, 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 mve zsh:
mv -t -- new_place ${(f)"$(<file_list.txt)"}
Ou com GNU mve GNU xargse 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