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

发布于 2024-11-09 07:37:52 字数 730 浏览 1 评论 0原文

我正在尝试使用一些很酷的 conky 配置来重新组织我的桌面。由于我非常喜欢 Emacs 中的 org 模式,因此我想从保存日常任务的 org 文件中导出任务并将其显示在 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

并且我可以计算 的出现次数>** with:

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

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

I'm trying to reorganise my desktop with some cool conky config. Since I'm a very big fan of org-mode in Emacs, I'd like to pipe out the tasks from org file where I keep my daily tasks and display it in conky. Say I have a file like this:

* first item
** subitem
** subitem
** subitem
* second item
** subitem
** subitem
* third item
** subitem
** subitem
** subitem
** subitem

I'd like to create a summary of my tasks that will check all tasks beginning with * and count ** items before it. Then I'd like to present that in a suitable maner:

* first item [3]
* second item [2]
* third item [4]

While I can find occurrences of strings beginning with only one * with grep:

grep "^\\* " foo.org

and I can count occurrences of ** with:

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

How can I achieve the desired result? Of course, one can use Python, or Ruby, but I'd like to stick with bash utilities only.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

妥活 2024-11-16 07:37:52

在您提供的示例文件上:

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

On the sample file you gave:

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

That returns the desired output.

* second item [2]
* first item [3]
* third item [4]

If you need it sorted, pipe the result in sort

awk command | sort -k2,2
匿名。 2024-11-16 07:37:52

这不是我的第一选择,但你可以在纯 bash 中执行此操作(无分叉):

#!/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}]"

需要指出的是:

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

It wouldn't be my first choice, but you can do this in pure bash (no forks):

#!/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}]"

Things to point out:

  • [[ ... =~ ... ]] is a bash extension allowing regex matches
  • declare -p is used to test for variable existance
  • The script will do funny things if the input isn't as described, e.g. empty lines, lines without the * or ** prefix
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文