Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 使用bash文本实用程序计算字符串匹配后的出现次数_Regex_Bash_Sed_Awk_Grep - Fatal编程技术网

Regex 使用bash文本实用程序计算字符串匹配后的出现次数

Regex 使用bash文本实用程序计算字符串匹配后的出现次数,regex,bash,sed,awk,grep,Regex,Bash,Sed,Awk,Grep,我正试图用一些很酷的conky配置重新组织我的桌面。因为我非常喜欢Emacs中的组织模式,所以我想从我保存日常任务的组织文件中导出任务,并将其显示在conky中。假设我有这样一个文件: * first item ** subitem ** subitem ** subitem * second item ** subitem ** subitem * third item ** subitem ** subitem ** subitem ** subitem 我想创建一个任务摘要,它将检查以*

我正试图用一些很酷的conky配置重新组织我的桌面。因为我非常喜欢Emacs中的组织模式,所以我想从我保存日常任务的组织文件中导出任务,并将其显示在conky中。假设我有这样一个文件:

* first item
** subitem
** subitem
** subitem
* second item
** subitem
** subitem
* third item
** subitem
** subitem
** subitem
** subitem
我想创建一个任务摘要,它将检查以
*
开头的所有任务,并统计前面的
***
项。那么我想用合适的方式来表达:

* first item [3]
* second item [2]
* third item [4]
虽然我可以在
grep
中找到仅以一个
*
开头的字符串:

grep "^\\* " foo.org
我可以用以下方法计算
**
的出现次数:

grep -c "^\\*\{2\}" foo.org

我怎样才能达到预期的结果?当然,可以使用Python或Ruby,但我只想使用bash实用程序。

关于您提供的示例文件:

awk '!/^*/{next}$1=="*"{sub("\\*+ ","");p=$0}$1="**"{c[p]+=1}END{for(i in c) printf "* %s [%s]\n", i ,c[i]-1}'
返回所需的输出

* second item [2]
* first item [3]
* third item [4]
如果需要排序,请在
sort

awk command | sort -k2,2

这不是我的第一选择,但您可以在纯bash(无叉子)中实现这一点:

需要指出的事情:

  • [[…=~…]]
    是允许正则表达式匹配的bash扩展
  • declare-p
    用于测试变量是否存在
  • 如果输入不符合描述,脚本将执行有趣的操作,例如空行、没有*或**前缀的行

整洁。但是如果我有一行不是以
*
开头的,它仍然在“计数”它。使用grep管道到awk是多余的。我相应地更改了awk过滤器。你应该删除我的“调整”。真漂亮!塔克斯!但我注意到了一个奇怪的行为:
awk
为什么自己排序行?!我可以使用“排序”。。。没关系!=)@ripat,我喜欢关联数组,但我相信您可以使用awk以保留输入顺序的方式实现这一点:)
#!/bin/bash

set -u
unset HEADING LINE COUNT
COUNT=0
while read LINE; do
  if [[ "$LINE" =~ '^\* ' ]]; then
    #print previous, if it exists
    declare -p HEADING > /dev/null 2>&1 && echo "$HEADING [${COUNT}]"

    HEADING=$LINE
    COUNT=0
  elif [[ "$LINE" =~ '^\*\* ' ]]; then
    let COUNT++
  else
    echo "Unexpected input" 1>&2
  fi
done
echo "$HEADING [${COUNT}]"