删除第 n 行(从底部开始计算)

Swa*_*ule 8 sed awk perl

文件中的行数未知。如何在 Unix 平台上使用一行命令(如果需要可以使用多个)删除第 n 行(从底部开始计算)。

Pan*_*nki 17

例如,使用以下命令从底部删除第 4 行sed

tac input | sed '4d' | tac
Run Code Online (Sandbox Code Playgroud)

要覆盖输入文件:

tmpfile=$(mktemp)
tac input | sed '4d' | tac > "$tmpfile" && mv "$tmpfile" input
Run Code Online (Sandbox Code Playgroud)

  • 使用输出重定向写入新文件,然后替换原始文件。 (2认同)

Kam*_*ski 5

sed:

  • 如果n是 1:

    sed '$ d'
    
    Run Code Online (Sandbox Code Playgroud)

    这很简单:如果是最后一行,删除模式空间,这样它就不会被打印出来。

  • 如果n大于 1(并且可用作$n):

    sed "
       : start
       1,$((n-1)) { N; b start }
       $ { t end; s/^//; D }
       N
       P
       D
       : end
     "
    
    Run Code Online (Sandbox Code Playgroud)

    注意$((n-1))sed启动前由外壳展开。

    这个片段

    : start
    1,$((n-1)) { N; b start }
    
    Run Code Online (Sandbox Code Playgroud)

    在模式空间中存储n -1 行。如果sed在此循环中到达输入流的末尾,将自动打印模式空间(从末尾开始没有第 n 行,不会删除任何行)。

    假设有更多的输入。然后,在我们到达最后一行之前,迭代这个片段:

    N   # read the next line of input and append it to the pattern space
    P   # print the first line from the pattern space
    D   # delete the first line from the pattern space and start a new cycle
    
    Run Code Online (Sandbox Code Playgroud)

    这样,模式空间就是我们的缓冲区,它根据输入使输出“延迟”了几行。N从这个片段也能够读取输入的最后一行。

    读取最后一行后,将执行此操作:

    $ { t end; s/^//; D }
    
    Run Code Online (Sandbox Code Playgroud)

    这段代码第一次执行时,t不会跳转到,end因为之前没有成功的替换。s/^//然后执行这种无操作替换,并且模式空间中的第一行被删除 ( D) 而不打印。这正是您要删除的行。由于D开始了一个新的循环,同一行代码最终会再次执行。这次t将分支到end.

    sed到达脚本末尾时,将自动打印模式空间。这样所有剩余的行都会打印出来。

    该命令将为n=2(有效)和n=1(无效)生成相同的输出。我试图找到一个不管n都有效的解决方案。我失败了,因此是n为 1的特殊情况。