Bash unix命令,从单词的第一次和最后一次出现之间获取行并写入文件
我需要一个unix命令来查找单词第一次出现和最后一次出现之间的行 例如: 让我们假设我们有1000行。第十行包含单词“stackoverflow”,第三十五行也包含单词“stackoverflow”Bash unix命令,从单词的第一次和最后一次出现之间获取行并写入文件,bash,shell,unix,grep,perl,Bash,Shell,Unix,Grep,Perl,我需要一个unix命令来查找单词第一次出现和最后一次出现之间的行 例如: 让我们假设我们有1000行。第十行包含单词“stackoverflow”,第三十五行也包含单词“stackoverflow” 我想打印10到35行,并将其写入新文件。如果您知道可以有多少行的上限(比如一百万行),那么您可以使用以下简单的滥用脚本: (grep -A 100000 stackoverflow | grep -B 1000000 stackoverflow) < file 你可以分两步完成。其基本思想是
我想打印10到35行,并将其写入新文件。如果您知道可以有多少行的上限(比如一百万行),那么您可以使用以下简单的滥用脚本:
(grep -A 100000 stackoverflow | grep -B 1000000 stackoverflow) < file
你可以分两步完成。其基本思想是: 1) 获取第一个和最后一个匹配的行号 2) 打印这些范围之间的行范围
$ read first last <<< $(grep -n stackoverflow your_file | awk -F: 'NR==1 {printf "%d ", $1}; END{print $1}')
$ awk -v f=$first -v l=$last 'NR>=f && NR<=l' your_file
按步骤:
$ grep -n stackoverflow a
3:stackoverflow
9:stackoverflow
11:stackoverflow
$ grep -n stackoverflow a | awk -F: 'NR==1 {printf "%d ", $1}; END{print $1}'
3 11
$ read first last <<< $(grep -n stackoverflow a | awk -F: 'NR==1 {printf "%d ", $1}; END{print $1}')
$ echo "first=$first, last=$last"
first=3, last=11
$grep-n堆栈溢出a
3:堆栈溢出
9:堆栈溢出
11:堆栈溢出
$grep-n stackoverflow a | awk-F:'NR==1{printf“%d”,$1};结束{打印$1}'
3 11
$read first last使用:
这背后的想法是使用“stackoverflow”字符串将整个输入文件的数组输入到块中进行拆分。接下来,我们用join“stackoverflow”将第二个匹配项打印到最后一个-1中。我不能100%确定输出是否应该包含第一个和最后一个匹配行,所以我假设它是。但如果我们想要独占,这一点很容易改变
此纯bash解决方案只需一步即可完成所有工作,即文件(或管道)只读取一次:
#!/bin/bash
function midgrep {
while read ln; do
[ "$saveline" ] && linea[$((i++))]=$ln
if [[ $ln =~ $1 ]]; then
if [ "$saveline" ]; then
for ((j=0; j<i; j++)); do echo ${linea[$j]}; done
i=0
else
saveline=1
linea[$((i++))]=$ln
fi
fi
done
}
midgrep "$1"
这项工作如下:
$ cat input.txt | ./midgrep.sh stackoverflow
- 在数组的第一个元素中查找第一个匹配行和缓冲区
- 继续读取行,直到下一个匹配,并在执行时缓冲到数组
- 在每个后续匹配上,刷新缓冲区数组以输出
- 继续读取文件到最后。如果没有更多的匹配项,那么最后一个缓冲区将被丢弃
这种方法的优点是我们只读取一次输入。缺点是我们在每个匹配之间缓冲所有内容-如果每个匹配之间有很多行,那么这些都会缓冲到内存中,直到我们进行下一个匹配
此外,它还使用bash=~
正则表达式操作符来保持这个纯bash。但是,如果您对grep更满意的话,您可以将其替换为grep。与其想象,不如创建一个示例输入文件和预期输出,供我们处理?
perl -00 -lne '
chomp(my @arr = split /stackoverflow/);
print join "\nstackoverflow", @arr[1 .. $#arr -1 ]
' file.txt | tee newfile.txt
#!/bin/bash
function midgrep {
while read ln; do
[ "$saveline" ] && linea[$((i++))]=$ln
if [[ $ln =~ $1 ]]; then
if [ "$saveline" ]; then
for ((j=0; j<i; j++)); do echo ${linea[$j]}; done
i=0
else
saveline=1
linea[$((i++))]=$ln
fi
fi
done
}
midgrep "$1"
$ cat input.txt | ./midgrep.sh stackoverflow