我需要遍历有时包含空格的列表。
这是我现在使用的脚本
locate .txt > list
for book in $(cat list)
do
cp "${book}" /mnt/e/BOOK
done
然后,我需要将所有 .txt 文件复制到指定目录中。当我的列表包含以下内容时,我不会遇到任何麻烦
/mnt/d/txtfiles/mytextfile1.txt
但是当脚本迭代时说
/mnt/d/txtfiles/My text . File2.txt
由于空格,我在迭代时遇到问题,而列表文件路径在一行中。
答案1
要处理任意文件名,您需要列表使用不能出现在文件路径中的字节作为分隔符。唯一起作用的是字节 0。
假设 GNU 工具:
locate -0 '*.txt' |
xargs -r0 cp -it /mnt/e/BOOK
或者与zsh
:
cp -i ${(0)"$(locate -0 '*.txt')"} /mnt/e/BOOK/
(但请注意,与该方法相反xargs
,如果文件列表太大,则可能会失败;在这种情况下,可以通过运行多次调用来解决此问题。如果没有匹配的文件,xargs
您还会收到错误消息)cp
这些0
用于对 NUL 分隔记录而不是行进行操作的选项或参数扩展标志是专门设计用于处理文件路径列表的。
文本行(在 *nix 上是有限数量的字符(不是字节)的换行符分隔序列)通常不能保存文件路径,因为文件路径不能保证是文本并且可能包含换行符。
您的$(cat list)
,因为它是列表上下文中不带引号的命令替换,因此在大多数类似 Bourne 的 shell 中会经历 IFS-split+glob ,而仅在zsh
.
在这里,您需要将 更改locate
为locate -0
以便list
包含 NUL 分隔记录的列表,调整 IFS-split 以便它在 NUL 上拆分并确保glob
未启用。
然而,只有在其他 shell 不支持在其变量中存储 NUL 时才IFS=$'\0'
有效,但使用如上所示的参数扩展标志(显式分割运算符)比全局更改要好得多。zsh
zsh
0
IFS
在 4.4 或更高版本的 shell中bash
,另一种方法是:
locate -0 '*.txt' > list &&
readarray -td '' list < list &&
cp -i "${list[@]}" /mnt/w/book
或者没有list
文件中介:
readarray -td '' list < <(locate -0 '*.txt') &&
cp -i "${list[@]}" /mnt/w/book
另请注意,这将返回路径中任何位置locate .txt
的所有条目。例如,.txt
这可能包括。只会返回那些路径/foo.txting/bar.mp4
locate '*.txt'
结尾在.txt
。例如,如果您仍然想包含.txt.gz
或文件,但仅在文件名中查找,而不是完整路径,请使用..txt.in
.txt
locate -0 -b .txt