find返回的字符串在在中间被分隔



我是shell(bash)脚本的新手。在终端上,find表现为:

find . -name 'Ado*'
./Adobe ReaderScreenSnapz001.jpg
./Adobe ReaderScreenSnapz002.jpg

然而,我的shell脚本似乎用"Adobe"后面的空格来分隔文件名。

代码:

#!/bin/sh
i=1
for base_name in `find . -name "Ado*"`
do
echo $base_name
 :
i=$((i+1))
done

它返回类似于:

./Adobe
ReaderScreenSnapz001.jpg
 :

哪里出了什么问题?

到目前为止,大多数答案都使用了有效的find ... | while read ...,但while循环在子shell中运行(因为它是管道的一部分),因此当子shell退出时,文件数($i)将丢失。如果您正在使用bash(即您的shebang必须#!/bin/bash,而不是#!/bin/sh),则可以使用其进程替换功能来避免此问题:

i=1
while IFS= read -r -u3 -d '' base_name; do
    echo "$base_name"
    :
    i=$((i+1))
done 3< <(find . -name "Ado*" -print0)

我在这里还添加了一些其他技巧,使其更加健壮:我将IFS设置为null(仅用于读取命令),这样它就不会修剪文件名中的前导或尾部空白;我使用read的-r选项,这样它就不会在文件名中使用反斜杠做有趣的事情;我使用find的-print0和read的-d ''来使用空字节作为文件分隔符,这样它甚至不会被文件名中的换行符混淆;我在循环中的$base_name周围使用双引号,所以它也不会在空白处被拆分(对echo来说不重要,但如果你真的尝试将文件名用作文件名,那就很重要了);最后,我通过fd#3而不是#0(stdin)传递文件列表,其中包含3<和read的-u3选项,这样,如果循环中的任何内容从stdin读取,它就不会意外地吸入一堆文件名。

find . -name 'Ado*'
./Adobe ReaderScreenSnapz001.jpg
./Adobe ReaderScreenSnapz002.jpg

CCD_ 11的结果包含CCD_
因此,下面的for loop4项进行迭代。

您可以将脚本更改为:

i=1
find . -name 'Ado*' | while read base_name
do
    echo $base_name
    :
    i=$((i+1))
done

您的shell将for base_name in $(find . -name "Ado*")替换为
for base_name in ./Adobe ReaderScreenSnapz001.jpg ./Adobe ReaderScreenSnapz002.jpg

因此,for看到四个单词:
-./Adobe
-ReaderScreenSnapz001.jpg
-./Adobe
-ReaderScreenSnapz002.jpg

我的建议:用while read base_name 代替for base_name in

#!/bin/sh
i=1
find . -name "Ado*" |
while read base_name
do
echo $base_name
 :
i=$((i+1))
done

CCD_ 24逐行读取并在其输入端停止CCD_ 25循环(find
CCD_ 27将每一行存储在CCD_ 28变量中。

您的shell脚本中没有任何错误。

当您在反引号之间调用程序时,该命令将在分叉进程中执行,结果将返回给主程序进行lexed和解析。作为一个字符串,结果被分成几个标记。

你应该像那样使用read内置

#! /bin/sh
i=0
find . -name 'Ado*' | while read result
do
echo $result
i=$((i+1))
done

最新更新