【问题标题】:How can I grep a list of names from case?如何从案例中获取名称列表?
【发布时间】:2020-08-18 14:24:29
【问题描述】:

举个例子,我有一堆应用程序不断地写入 /var/log/app//nonsence.file 没有其他文件夹,只是来自这一组应用程序的日志。所以我可以轻松做到:

cat /var/log/app/*/nonsence.file 我会得到一个很好的应用日志流。

在此流中混入定期对人的引用。我想构建一个脚本以在某些名称出现在流中时触发。

我可以很容易地做到这一点:

cat /var/log/app/*/nonsence.file | grep '格雷格|约翰|苏西|斯泰西' 这样我就可以将其放入一个简单的脚本中:

#!/bin/sh
NAME=`cat /var/log/app/*/nonsence.file | grep 'greg\|john\|suzy\|stacy'`
case "$NAME" in
  "greg" ) echo "I found greg!" >> ~/names.meh ;;
  "john" ) echo "I found john!" >> ~/names.meh ;;
  "suzy" ) echo "I found suzy!" >> ~/names.meh ;;
  "stacy" ) echo "I found stacy!" >> ~/names.meh ;;
  * ) echo "forever alone..." >> ~/names.meh ;;
esac

简单易懂!

麻烦的是,名字列表时常变化,我真的想要一个更整洁的列表。

经过一番思考,我相信我真正想做的只是将每个名称添加到案例部分。那么我需要在 NAME 变量部分做什么来告诉命令 grep 案例部分中引用的名称?

【问题讨论】:

  • 那么...grep -o?还有grep -f?你读过grep 手册吗?而您的case 缺少;;
  • 是的,那里的脚本只是一个示例。我知道我错过了;;我发布的那一刻,但懒得编辑。
  • 至于 grep 手册,是的,我读过它,这就是为什么我知道我可以 grep 两个位置,但正如我所问的,这是最好的方法吗?我的意思是,每次有新名称时我都必须更新脚本,我想我真正的问题是,我如何告诉 NAME 变量 grep 每个案例条目的触发器是什么?
  • 你知道吗...无论如何这是一个更好的方法...我想我需要编辑我的问题。
  • 如何cat * | grep -wof name.list | sort -u 并将您想要找到的所有名称存储在name.list 中?

标签: bash shell


【解决方案1】:

cat file | grepcat 的无用用法。只需grep file

管道中的命令默认是块缓冲的。

>> ~/names.meh 只是重复。只需为整个块指定一次。

不鼓励使用反引号 `。最好改用$(..)

每次分配NAME=... 时,文件都会被读取,而您似乎想要:

...我想构建一个脚本来触发某些名称出现在流中。

这表明您希望名称出现在脚本中时做出反应,而不是在一段时间之后。

你可以试试:

patterns=(greg john suzy stacy)
printf "%s\n" /var/log/app/*/nonsence.file |
# tail each file at the same time by spawning for each a background process
xargs -P0 -n1 tail -F -n+1 |
#  grep for the patterns
# pass the patterns from a file
# the <(...) is a process substitution, a bash extension
grep --line-buffered -f <(printf "%s\n" "${patterns[@]}") -o |
# for each grepped content execute different action
while IFS= read -r line; do
    case "$line" in)
    "greg") someaction; ;;
     # etc
     *) echo "Internal error - unhandled pattern"; ;;
    esac
done >> ~/names.me

因为指定模式两次是蹩脚,你可以做一个关联函数来将模式映射到函数名,或者只使用唯一的函数名并从中生成模式列表:

pattern_greg() { echo "greg"; }
pattern_kamil() { echo "well, not greg"; }

patterns=($(declare -F | sed 's/declare -f //; /^pattern_/!d; s/pattern_//'))
... |
while IFS= read -r line; do
     if declare -f pattern_"$line" >/dev/null 2>&1; then
        pattern_"$line"
     else
        echo "Internal error occured"
     fi
done

或者,但我更喜欢这些功能:

greg_function() { echo do something; }
kamil_callback() { echo do something else; }
declare -A patterns
patterns=([greg]=greg_function [kamil]=kamil_callback)
... | grep -f <(printf "%s\n" ${!patterns[@]}) ... | 
while IFS= read -r line; do
     # I think this is how to check if array element is set
     if [[ -n "${patterns[$line]}" ]]; then
            "${patterns[$line]}"
     else
         echo error
     fi
done

【讨论】:

  • 这行得通!虽然我不希望只输入一次以上的名称,但这至少将名称放在一个地方并使它们更易于使用(因为它们位于脚本的顶部并且相当容易阅读)
  • 我认为您可以定义与模式相同的名称,然后就像 greg() { echo do something; }; .... while IFS= read -r line; do "$line"; done 或更好地为函数创建一个关联的名称数组。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-01
  • 2022-08-03
  • 1970-01-01
  • 2017-08-20
  • 2015-09-28
  • 2013-08-22
相关资源
最近更新 更多