这$(cat file_list.txt)
在POSIX炮弹一样bash
在列表环境是割裂+水珠操作(zsh
仅做了拆分正如你所期望的部分)。
它分割为 $IFS
(默认情况下为SPC,TAB和NL),并且会进行glob,除非您完全关闭glob。
在这里,您只想在换行符上分割,并且不想要glob部分,因此应该是:
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
这也具有优势(相对于 while read
循环),可以丢弃空行,保留尾随的未终止行,并保留mv
的stdin(例如在出现提示时需要)。
尽管确实有缺点,但文件的全部内容必须存储在内存中(多次使用诸如 bash
和zsh
)。
对于某些壳(ksh
,zsh
以及在较小程度上bash
),可以使用优化它$(<file_list.txt)
代替$(cat file_list.txt)
。
要使用while read
循环进行等效操作,您需要:
while IFS= read <&3 -r file || [ -n "$file" ]; do
{
[ -n "$file" ] || mv -- "$file" "new_place/$file"
} 3<&-
done 3< file_list.txt
或搭配bash
:
readarray -t files < file_list.txt &&
for file in "${files[@]}"
[ -n "$file" ] || mv -- "$file" "new_place/$file"
done
或搭配zsh
:
for file in ${(f)"$(<file_list.txt)"}
mv -- "$file" "new_place/$file"
done
或与GNU mv
和zsh
:
mv -t -- new_place ${(f)"$(<file_list.txt)"}
或者使用GNU mv
和GNU xargs
以及ksh / zsh / bash:
xargs -rd '\n' -a <(grep . file_list.txt) mv -t -- new_place
有关在不考虑在bash / POSIX shell中引用变量的安全性隐含含义的情况下保留扩展名的含义的更多信息,请参见