Bash unix命令,从单词的第一次和最后一次出现之间获取行并写入文件

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 你可以分两步完成。其基本思想是

我需要一个unix命令来查找单词第一次出现和最后一次出现之间的行

例如:

让我们假设我们有1000行。第十行包含单词“stackoverflow”,第三十五行也包含单词“stackoverflow”


我想打印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