将管道结果分配给变量

时间:2013-05-31 18:53:08

标签: bash unix pipeline

我想计算*.sav文件夹中$1个文件的数量。 我尝试使用以下命令,但它不起作用,有什么问题?

numOfFiles=`ls $1 | grep -o *\.sav | wc -w`

5 个答案:

答案 0 :(得分:4)

Do not parse the output from ls

改为使用bash数组。

shopt -s nullglob
sav_files=(*.sav)
echo ${#sav_files[@]}

答案 1 :(得分:1)

主要问题是* .sav不是正则表达式,它是一个glob。你可能想要\.sav grep,你必须为shell转义一次,再次因为过时的``语法:

numOfFiles=`ls $1 | grep -o \\\\.sav | wc -w`

此外,您不应解析ls的输出,而wc -w会导致带有空格的文件名被多次计数。

更好的解决方案是使用find:

numOfFiles=$(find "$1" -maxdepth 1 -name '*.sav' | wc -l)

对于更好的Bash特定解决方案,请参阅1_CR的答案。

答案 2 :(得分:1)

不希望在文件计数中搜索假设问题,但解析ls的输出有时可能是错误的想法。亲自尝试,创建一个文件:

touch 'aa bb
cc.sav'

因此,请在名称中创建spacenewline的文件。通常任何ls解析都会失败。

1_CR的解决方案是NICE和ELEGANT。

如果由于某些原因不喜欢它,您可以使用find并且不要使用wc,因为wc例如失败是最后一行不包含换行符。 (wc不计算行数,而是\n个字符。

接下来将给出正确答案:

numOfFiles=$(find . -maxdepth 1 -name \*.sav -print0 | grep -zc .)

find -print0打印所有找到的文件“零结束”,grep -z可以读取零划分的“行”。 -c简单计数找到模式.(任何字符)

的行

答案 3 :(得分:0)

您的正则表达式错误,*grep的重复运算符,但您没有指定要重复的内容。

无论如何,grep是不必要的;只需将模式指定为shell glob。

numOfFiles=`ls "$1"/*.sav | wc -l`

请注意$1周围的引号以及使用行数而不是字数;对于wc -wunderscore_filename将返回两个计数。

如果你确实使用grep,那么将搜索模式放在单引号中通常是个好主意,因此你不必使用反斜杠转义shell元字符。 (即使使用反斜杠,你的模式最终也会被转义,因为shell会在未加引号的字符串中占用一级转义。)

如果当前目录中的*.sav上有任何匹配项,那么未引用的正则表达式将由shell扩展为glob,并产生有趣的结果,这可能很难调试。

答案 4 :(得分:0)

就个人而言,我建议在变量周围使用引号以防止出现空格问题。

此外,wc -l是一个更好的解决方案,因为它计算行而不是单词(带空格的文件可能会计数两次)。

所以试试这个:

numOfFiles=$(ls -1 "$1/"*.sav | wc -l)