我想查找文件中出现特定单词的行以及行号,并将行号放入数组中。如何在 bash 中做到这一点?

我想查找文件中出现特定单词的行以及行号,并将行号放入数组中。如何在 bash 中做到这一点?

这会返回行号,但它们位于字符串中:

grep -n -F -w $word $file | cut -d : -f 1

答案1

我会用awk这个,而不是grepand cut。要将行号放入数组中,请使用流程替代以及 bash 内置功能( in bashmapfile的同义词是,但您可以通过运行在 bash 中获得比bash 更好、更详细的帮助)。例如:mapfilereadarrayhelp mapfilehelp readarray

mapfile -t array < <(awk -v w="$word" '$0 ~ w {print NR}' "$file")

或者,使用固定字符串匹配而不是正则表达式匹配:

mapfile -t array < <(awk -v w="$word" 'index($0,w) {print NR}' "$file")

这两者都通过 awk 的选项将 shell 变量传递$word给 awk 变量,因此无论它包含什么字符串都是安全的。比在双引号 awk 脚本中使用 $word 安全得多。w-v

值得注意的是:如果有多个输入文件,您可能希望打印FNR而不是NR。NR 是迄今为止读取的所有行的累计总数。FNR 是行号当前文件仅有的。 (当我说“行”时,我真正的意思是“记录”,因为 awk 能够处理的不仅仅是带有换行符分隔记录的纯文本文件)

答案2

要将bash行的内容读入数组,您可以使用readarray -t(又名mapfile,尽管这是一个用词不当,因为没有映射并且没有文件这里会导致与zsh/mapfile模块zsh及其$mapfile特殊关联数组(真正映射文件)的混淆:

readarray -t array < <(
  grep -nFwe "$word" -- "$file" | cut -d : -f 1
)

(顺便说一句,您忘记了扩展周围的--和/或-e和引号)。

或者,您可以使用 split+glob 运算符,并且由于它都是数字,因此您可以跳过禁用 glob:

IFS=$'\n'
array=( $(grep -nFwe "$word" -- "$file" | cut -d : -f 1) )

这样做的好处是可以保留管道的退出状态。

在 zsh 中,您可以使用f参数扩展标志来分割在线feed,而无需修改$IFS.

array=( ${(f)"$(grep -nFwe "$word" -- "$file" | cut -d : -f 1)" } )

不过,默认值$IFS也可以在这里使用(并且没有什么理由$IFS在 zsh 中进行修改):

array=( $(grep -nFwe "$word" -- "$file" | cut -d : -f 1) )

相关内容