如何循环遍历包含空格的列表?

如何循环遍历包含空格的列表?

我需要遍历有时包含空格的列表。

这是我现在使用的脚本

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.

在这里,您需要将 更改locatelocate -0以便list包含 NUL 分隔记录的列表,调整 IFS-split 以便它在 NUL 上拆分并确保glob未启用。

然而,只有在其他 shell 不支持在其变量中存储 NUL 时才IFS=$'\0'有效,但使用如上所示的参数扩展标志(显式分割运算符)比全局更改要好得多。zshzsh0IFS

在 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.mp4locate '*.txt'结尾.txt。例如,如果您仍然想包含.txt.gz或文件,但仅在文件名中查找,而不是完整路径,请使用..txt.in.txtlocate -0 -b .txt

相关内容