我是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
:
哪里出错了?
答案 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
变量中。