我是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 loop
对4
项进行迭代。
您可以将脚本更改为:
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