find返回的字符串在中间分开

时间:2012-02-05 00:04:37

标签: bash shell

我是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
 :

哪里出错了?

4 个答案:

答案 0 :(得分:3)

到目前为止,大多数答案都使用了find ... | while read ...,但是while循环在子shell中运行(因为它是管道的一部分),所以当你的文件数量($ i)丢失时子shell退出。如果您正在使用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而不是带#{1}的#0(stdin)传递文件列表并读取3<选项,所以如果循环内的任何内容从stdin读取,它将不会意外地吸入一堆文件名。

答案 1 :(得分:1)

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

find结果包含white-spaces 因此,以下for loop遍历4个项目。

您可以将脚本更改为:

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

答案 2 :(得分:1)

你的shell脚本没有错。

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

你应该像这样使用read builtin

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

答案 3 :(得分:1)

你的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

我的建议:将for base_name in替换为while read base_name

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

read一行一行地读取并在输入结束时停止while循环(find)。
read将每行存储在base_name变量中。