Rằng $(cat file_list.txt)
trong các vỏ POSIX như bash
trong ngữ cảnh danh sách là toán tử split + global ( zsh
chỉ thực hiện phần tách như bạn mong đợi).
Nó phân tách trên các ký tự của $IFS
(theo mặc định, SPC , TAB và NL) và thực hiện toàn cầu trừ khi bạn tắt hoàn toàn toàn cầu.
Tại đây, bạn chỉ muốn phân chia trên dòng mới và không muốn phần toàn cầu, vì vậy nó phải là:
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
Điều đó cũng có lợi thế (qua một while read
vòng lặp) để loại bỏ các dòng trống, bảo toàn một dòng cuối bị xóa và bảo toàn mv
stdin (cần thiết trong trường hợp nhắc nhở chẳng hạn).
Mặc dù vậy, nó có nhược điểm là toàn bộ nội dung của tệp phải được lưu trong bộ nhớ (nhiều lần với các shell như bash
và zsh
).
Với một số vỏ ( ksh
, zsh
và đến một mức độ thấp hơn bash
), bạn có thể tối ưu hóa nó với $(<file_list.txt)
thay vì $(cat file_list.txt)
.
Để thực hiện tương đương với một while read
vòng lặp, bạn cần:
while IFS= read <&3 -r file || [ -n "$file" ]; do
{
[ -n "$file" ] || mv -- "$file" "new_place/$file"
} 3<&-
done 3< file_list.txt
Hoặc với bash
:
readarray -t files < file_list.txt &&
for file in "${files[@]}"
[ -n "$file" ] || mv -- "$file" "new_place/$file"
done
Hoặc với zsh
:
for file in ${(f)"$(<file_list.txt)"}
mv -- "$file" "new_place/$file"
done
Hoặc với GNU mv
và zsh
:
mv -t -- new_place ${(f)"$(<file_list.txt)"}
Hoặc với GNU mv
và GNU xargs
và ksh / zsh / bash:
xargs -rd '\n' -a <(grep . file_list.txt) mv -t -- new_place
Đọc thêm về ý nghĩa của việc bỏ các phần mở rộng không được trích dẫn tại hàm ý Bảo mật của việc quên trích dẫn một biến trong shell bash / POSIX