如何使用“find”命令在文件名包含空格的目录中搜索文件?

3

我如何使用find命令在包含空格的目录中搜索文件?我使用脚本。

#!/bin/bash
for i in `find "/tmp/1/" -iname "*.txt" | sed 's/[0-9A-Za-z]*\.txt//g'`
do
    for j in `ls "$i" | grep sh | sed 's/\.txt//g'`
    do
        find "/tmp/2/" -iname "$j.sh" -exec cp {} "$i" \;
    done
done

但是包含空格的文件和目录名称不会被处理?

1
问题不在于 find,而是在于 for 循环,因为“空格”被视为项之间的分隔符。 - Sylvain Leroux
2
你在这里究竟想做什么? - skamazin
@SerjAntiquity:“我希望这个脚本能够搜索与该 .txt 文件同名的文件,并将它们复制到该 .txt 文件所在的目录。” 如果您复制一个与原文件同名(包括扩展名 .txt)的文件,那么它将被覆盖。这是您期望的行为吗? - Sylvain Leroux
@Sylvain Leroux,不,我复制了一个文件,文件名相同,但扩展名不同(.sh)。 - Stoned_Fox
@SerjAntiquity,目前为止,有许多答案试图修复您可能不够优化的解决方案。我可以建议您重新表述您在先前评论中所解释的内容,然后编辑您的问题(甚至发布另一个问题)——专注于_您所尝试做的事情_。 - Sylvain Leroux
显示剩余3条评论
6个回答

6
这将获取所有文件名中包含空格的文件。
$ls
more space  nospace  stillnospace  this is space
$find -type f -name "* *"
./this is space
./more space

过滤器只针对常规文件类型,缺少对目录文件类型的过滤。在你的示例中,目录文件将不会被过滤。 - deimus

3

我不知道如何实现你的目标。但鉴于你的实际解决方案,问题并不是在于find,而是在for循环中,“空格”被作为项之间的分隔符。

find在这种情况下有一个有用的选项:

来自man find:

-print0

True; 将完整文件名打印到标准输出,后面跟着一个空字符(而不是- print使用的换行符)。这使得包含换行符或其他类型的空格的文件名可以被正确解释,以便处理find输出的程序能够处理它们。此选项对应于xargs的-0选项。

正如文档所述,这将与xargs-0选项匹配。其他几个标准工具也有相应的选项。您可能需要重写复杂的管道以围绕这些工具,以便清理处理包含空格的文件名。

此外,请参见bash“ for in”循环在null限定字符串变量上循环,了解如何使用0结尾的参数使用for循环


1

这样做:

find . -type f -name "* *"

你可以替换 . 来指定你想要查找符合条件的文件的路径。


0

你的第一个for循环是:

for i in `find "/tmp/1" -iname "*.txt" | sed 's/[0-9A-Za-z]*\.txt//g'`

如果我理解正确的话,它是在寻找 /tmp/1 目录中的所有文本文件,然后尝试使用 sed 命令删除文件名,对吧?这将导致一个包含多个 .txt 文件的目录被内部 for 循环处理多次。这符合您的要求吗?

您可以使用 dirname 代替 sed 来摆脱文件名。此外,在稍后的操作中,您使用 sed 来摆脱扩展名。您可以使用 basename 来实现。

for i in `find "/tmp/1" -iname "*.txt"` ; do
  path=$(dirname "$i")
  for j in `ls $path | grep POD` ; do
    file=$(basename "$j" .txt)
    # Do what ever you want with the file

这并不能解决一个目录被多次处理的问题,但如果这对你来说是个问题,你可以使用上面的for循环将文件名存储在数组中,然后使用sortuniq去除重复项。


我希望脚本能够搜索与 .txt 相同名称的文件,并将它们复制到源 .txt 所在的目录中。 - Stoned_Fox

0

使用带有从find输出的空值分隔路径名的while read循环:

#!/bin/bash
while IFS= read -rd '' i; do
    while IFS= read -rd '' j; do
        find "/tmp/2/" -iname "$j.sh" -exec echo cp '{}' "$i" \;
    done <(exec find "$i" -maxdepth 1 -mindepth 1 -name '*POD*' -not -name '*.txt' -printf '%f\0')
done <(exec find /tmp/1 -iname '*.txt' -not -iname '[0-9A-Za-z]*.txt' -print0)

0

从未使用过类似for i in $(find...)的语法,因为它对于包含空格的文件名会失败,就像你看到的那样。

改用find ... | while IFS= read -r i

没有样本输入和期望输出很难说清楚,但是这样的代码可能是你需要的:

find "/tmp/1/" -iname "*.txt" |
while IFS= read -r i
do
    i="${i%%[0-9A-Za-z]*\.txt}"
    for j in "$i"/*sh*
    do
        j="${j%%\.txt}"
        find "/tmp/2/" -iname "$j.sh" -exec cp {} "$i" \;
    done
done

以上代码仍然无法处理包含换行符的文件名。如果您遇到这种情况并且无法修复文件名,则可以考虑使用-print0选项来查找,并将其传输到xargs -0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接