grep -v:如何仅排除匹配的前(或最后)N 行?

Gre*_*bet 6 grep text-processing

有时在其他表格数据中会有一些非常烦人的行,例如

column name | other column name
-------------------------------
Run Code Online (Sandbox Code Playgroud)

我通常更喜欢通过grep -ving 一个合理唯一的字符串来删除不应该存在的垃圾行,但这种方法的问题是,如果合理唯一的字符串意外出现在数据中,那将是一个严重的问题。

有没有办法限制grep -v可以删除的行数(比如 1)?对于加分,有没有办法从末尾计算行数而不诉诸于<some command> | tac | grep -v <some stuff> | tac

don*_*sti 5

您可以使用awk忽略匹配的前n行(例如,假设您只想从文件中删除第一个和第二个匹配项):

n=2
awk -v c=$n '/PATTERN/ && i++ < c {next};1' infile
Run Code Online (Sandbox Code Playgroud)

要忽略匹配的最后n行:

awk -v c=${lasttoprint} '!(/PATTERN/ && NR > c)' infile
Run Code Online (Sandbox Code Playgroud)

哪里${lasttoprint}n文件中第 1 个到最后一个匹配项的行号。有多种方法可以获得该行号。(例如,通过sed/ 之类的工具仅打印每个匹配项的行号awk,然后tail | head提取它)...这是一种方法gnu awk

n=2
lasttoprint=$(gawk -v c=$((n+1)) '/PATTERN/{x[NR]};
END{asorti(x,z,"@ind_num_desc");{print z[c]}}' infile)
Run Code Online (Sandbox Code Playgroud)


Val*_*yKr 2

sed提供了一个更简单的方法:

... |  sed '/some stuff/ {N; s/^.*\n//; :p; N; $q; bp}' | ...
Run Code Online (Sandbox Code Playgroud)

这样您就可以删除第一个出现的位置。

如果你想要更多:

sed '1 {h; s/.*/iiii/; x}; /some stuff/ {x; s/^i//; x; td; b; :d; d}'
Run Code Online (Sandbox Code Playgroud)

,其中 count ofi是出现次数(一次或多次,而不是零)。

多行解释

sed '1 {
    # Save first line in hold buffer, put `i`s to main buffer, swap buffers
    h
    s/^.*$/iiii/
    x
}

# For regexp what we finding
/some stuff/ {
    # Remove one `i` from hold buffer
    x
    s/i//
    x
    # If successful, there was `i`. Jump to `:d`, delete line
    td
    # If not, process next line (print others).
    b
    :d
    d
}'
Run Code Online (Sandbox Code Playgroud)

此外

也许,这个变体会工作得更快,因为它会读取所有其余行并一次性打印它们

sed '1 {h; s/.*/ii/; x}; /a/ {x; s/i//; x; td; :print_all; N; $q; bprint_all; :d; d}'
Run Code Online (Sandbox Code Playgroud)

结果

您可以将此代码放入您的外壳.bashrc(或外壳的配置中,如果是其他外壳):

dtrash() {
    if [ $# -eq 0 ]
    then
        cat
    elif [ $# -eq 1 ]
    then
        sed "/$1/ {N; s/^.*\n//; :p; N; \$q; bp}"
    else
        count=""
        for i in $(seq $1)
        do
            count="${count}i"
        done
        sed "1 {h; s/.*/$count/; x}; /$2/ {x; s/i//; x; td; :print_all; N; \$q; bprint_all; :d; d}"

    fi
}
Run Code Online (Sandbox Code Playgroud)

并以这种方式使用它:

# Remove first occurrence
cat file | dtrash 'stuff' 
# Remove four occurrences
cat file | dtrash 4 'stuff'
# Don't modify
cat file | dtrash
Run Code Online (Sandbox Code Playgroud)