【问题标题】:How to store NUL output of a program in bash script?如何在 bash 脚本中存储程序的 NUL 输出?
【发布时间】:2016-09-28 10:11:10
【问题描述】:

假设有一个目录 'foo' 包含几个文件:

ls foo:
1.aa 2.bb 3.aa 4.cc

现在在 bash 脚本中,我想计算 'foo' 中具有特定后缀的文件的数量,并显示它们,例如:

SUFF='aa'
FILES=`ls -1 *."$SUFF" foo`
COUNT=`echo $FILES | wc -l`
echo "$COUNT files have suffix $SUFF, they are: $FILES"

问题是:如果SUFF='dd'$COUNT也等于1。 google了一下,发现原因是当SUFF='dd'$FILES是一个空字符串,并不是程序真正的null输出,wc会认为有一行。 NUL 输出只能通过管道传递。所以一种解决方案是:

COUNT=`ls -1 *."$SUFF" foo | wc -l`

但这会导致ls 命令被执行两次。所以我的问题是:有没有更优雅的方法来实现这一点?

【问题讨论】:

  • 文件名以foo结尾?你能给一个这样的样本名称吗?你也想在子目录中递归搜索吗?
  • foo 是目录。文件名以 aa,bb,cc 结尾。不需要搜索子目录。

标签: bash output store nul


【解决方案1】:
$ shopt -s nullglob
$ FILES=(*)
$ echo "${#FILES[@]}"
4
$ FILES=(*aa)
$ echo "${#FILES[@]}"
2
$ FILES=(*dd)
$ echo "${#FILES[@]}"
0
$ SUFFIX=aa
$ FILES=(*"$SUFFIX")
$ echo "${#FILES[@]}"
2
$ SUFFIX=dd
$ FILES=(*"$SUFFIX")
$ echo "${#FILES[@]}"
0

【讨论】:

  • 哇很好的解释!
  • @123:这很有趣,我没写过。您最近看过眼科医生吗?
  • 有没有一种简单的方法可以逐个输出FILES的内容?
  • 这是迄今为止最早也是最好的答案。所以答案本质上不是使用 ls 或 find 之类的程序,而是使用 bash 中内置的路径名扩展。
【解决方案2】:

你也可以试试这个;

#!/bin/bash
SUFF='aa'
FILES=`ls -1 *."$SUFF" foo`
FILENAMES=`echo $FILES | awk -F ':' '{print $2}'`
COUNT=`echo $FILENAMES | wc -w`
echo "$COUNT files have suffix $SUFF, they are: $FILENAMES"

如果在脚本中插入echo $FILES,则输出为foo: 1.aa 2.aa 3.aa 所以

awk -F ':' '{print $2}' 从 $FILES 变量中获取1.aa 2.aa 3.aa

wc -w 打印字数

【讨论】:

    【解决方案3】:

    如果您只需要文件计数,我实际上会使用find

    find '/path/to/directory' -mindepth 1 -maxdepth 1 -name '*.aa' -printf '\n' | wc -l
    

    这更可靠,因为它可以正确处理带有换行符的文件名。其工作方式是find 为每个匹配文件输出一个空行。

    编辑:如果要将文件列表保存在数组中,可以使用 glob:

    GLOBIGNORE=".:.."
    shopt -s nullglob
    FILES=(*aa)
    COUNT=${#arr[@]}
    echo "$COUNT"
    

    【讨论】:

    • 但我也想在脚本后面输出这些文件的名称。
    • @Inian 你是什么意思?
    • @Inian 这样做是因为它们只为每个文件名输出一个换行符,而不是实际的文件名
    • @Inian 是的,但 print0 也只在 gnu 上。
    • @123:我的错!以为是POSIX 标准,猜猜只有-print 是可移植的
    【解决方案4】:

    原因是bash中默认未设置选项nullglob:

    如果没有找到匹配的文件名,并且 shell 选项 nullglob 未启用,则单词保持不变。如果设置了 nullglob 选项,但没有找到匹配项,则删除该单词。

    所以,只需设置 nullglob 选项,然后再次运行您的代码:

    shopt -s nullglob
    SUFF='aa'
    FILES="$(printf '%s\n' foo/*."$SUFF")"
    COUNT="$(printf '%.0s\n' foo/*."$SUFF" | wc -l)"
    echo "$COUNT files have suffix $SUFF, they are: $FILES"
    

    或者更好:

    shopt -s nullglob
    suff='aa'
    files=( foo/*."$suff" )
    count=${#file[@]}
    echo "$count files have suffix $suff, they are: ${files[@]}"
    

    【讨论】:

    • 谢谢。但是如果文件名中包含\n,则可能会失败。
    • @xlwang 好的,解决了。 %.0s\n 每个文件只打印一个新行。
    猜你喜欢
    • 2020-09-05
    • 2021-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    相关资源
    最近更新 更多