使用shell脚本查找文件中从第n行开始的文本



我正试图从第n行开始在文件中搜索关键字。如果找到,则将变量设置为true例如,testtext.txt的文件内容:

abc-0
def-0
xyz-0
abc-1
xxx-1

我想从第三行开始搜索关键字"def",如果找到,打印true。同样假设第n行是传入值。

我有一个大致的想法,但不确定如何解决它。

#!/bin/bash
keyword=def
nthline=3
flag=false
count=$(awk 'NR>$nthline' ./testtext.txt | grep '$keyword' | wc -l)
if [[ $count -gt 0 ]];then
flag=true
fi
echo $flag

预期的输出应该是false,因为def在第三行之后不存在。

问题是我无法将"nthline"变量传递到NR>awk并且也不能将$keyword传递给上的grep

我已经使用实际值而不是传入进行了测试,它是有效的,所以命令应该是有效的。

count=$(awk 'NR>3' ./testtext.txt | grep 'def' | wc -l)

有没有办法做到这一点,或者其他更好的解决方案?

编辑:得到了一个几乎90%的解决方案,但我需要在标志为true之后分配变量。这就是我目前所拥有的,我不确定是否有更好的方法。

#!/bin/bash
flagz=false
tgt="def"
n=$1
flagz=$(awk -v tgt="$tgt" -v n="$n" flag="$flagz"'
FNR>=n && index($0,tgt){
print("true1")
exit
}
' ./testtext.txt)
echo "$flagz"

最好完全在awk中执行此操作,因为您已经在使用awk对文件进行切片。

示例:

tgt="def"
n=3
awk -v tgt="$tgt" -v n="$n" '
BEGIN{flag="false"}
FNR>=n && index($0,tgt){
flag="true"
exit
}
END{print flag}' file

或者,您可以制作一个管道,然后检查$?,看看grep是否找到您的匹配项:

tgt="def"
n=2
tail -n "+$n" file | grep "$tgt" >/dev/null

现在,如果grep找到该模式,则$?将是0,如果未找到,则为1。然后你可以设置这样的标志:

flag="false"
tail -n "+$n" file | grep "$tgt" >/dev/null 
[ $? ] && flag="true"

现在flag基于grep设置为true/false。命令tail -n +[some number] file将从绝对行号开始打印文件内容。

对于大文件,awk的效率要高得多,因为它在第一次匹配时就退出了。


根据更新进行编辑

问题是根据进程将Bash标志设置为truefalse

$?特殊参数是根据最近执行的前台管道的退出状态设置的因此,选择您的方法对文件进行切片并检测字符串,然后在管道之后立即基于$?在脚本中设置标志。请注意,testing$?在测试前重置$?,因此您需要在测试前捕获$?的值,或者在管道本身中使用它。

这些方法有效:

1(捕获$?和测试:

awk -v tgt="$tgt" -v n="$n" -v flag=1 '
FNR>=n && index($0,tgt){
flag=0
exit
}
END{ exit flag }
' ./testtext.txt 
res=$?
[ $res -eq 1 ] && flagz=false || flagz=true

2(捕获字符串结果并测试:

res=$(awk -v tgt="$tgt" -v n="$n" -v flag="false" '
FNR>=n && index($0,tgt) {
flag="true"
exit
}
END{ print flag }' ./testtext.txt)
[ $res = "false" ] && flagz=false || flagz=true

3(使用管道并在管道中进行测试:

tail -n "+$n" file | grep "$tgt" >/dev/null && flagz=true || flagz=false 

对于小文件,我的偏好是3,对于大文件,我更喜欢2

另一种方法是使用sed和一个范围表达式,告诉sed从第3行搜索到结束3,$。接受addr1,addr2的表达式的类型是有限的,但确实包括sed 's/find/replace/的传统替代形式。其中,您可以搜索包含def的整行,然后将其替换为&(整个匹配表达式的简写(。

要控制打印,请通过-n选项(抑制图案空间的正常打印(,并在替换表达式的末尾添加p(打印(,例如

sed -n '3,$ s/^.*def.*$/&/p' file

以上内容跳过前两行,并在第3行开始搜索/替换。

尝试:

tail -n "+$nthline" testtext.txt | grep -qF -- "$keyword" && flag=true || flag=false

建议:

awk 'NR > 3 && /def/{print 1}' testtext.txt

NR > 3表示如果记录总数大于3个&&,则在/def中找到查询defprint 1

相关内容

  • 没有找到相关文章

最新更新