使用 sed 或 awk 删除文件的倒数第三行

Delete third-to-last line of file using sed or awk

我有几个行号不同的文本文件,我必须删除所有文件中的倒数第三行。这是一个示例文件:

bear
horse
window
potato
berry
cup

此文件的预期结果:

bear
horse
window
berry
cup

我们可以删除文件的倒数第三行吗:
一种。不基于任何 string/pattern.
b.仅基于必须是倒数第三行的条件

我对如何从最后一行开始索引我的文件有疑问。我已经从倒数第二行的另一个 SO 问题中尝试了这个:

> sed -i 'N;$!P;D' output1.txt

有了tac + awk的解决方案,请你试试下面的方法。只需将 awkline 变量设置为你想跳过的行(从底部开始)。

tac Input_file | awk -v line="3" 'line==FNR{next} 1' | tac

解释: 使用tac 将读取Input_file 反向(从底行到第一行) ,将其输出传递给 awk 命令,然后检查条件是否 line 等于 line(我们想跳过)然后不打印该行,1 将打印其他行。

第二种解决方案:使用awk+wc解决方案,请尝试以下。

awk -v lines="$(wc -l < Input_file)" -v skipLine="3" 'FNR!=(lines-skipLine+1)' Input_file

解释: 在此处启动 awk 程序并创建一个变量 lines ,其中包含总行数存在于 Input_file 中。变量 skipLine 具有我们要从 Input_file 底部跳过的行号。然后在主程序中检查条件,如果当前行不等于 lines-skipLine+1 然后打印这些行。

第三个解决方案: 根据 Ed 先生的评论添加解决方案。

awk -v line=3 '{a[NR]=[=12=]} END{for (i=1;i<=NR;i++) if (i != (NR-line)) print a[i]}' Input_file

解释:为第三个解决方案添加详细解释。

awk -v line=3 '             ##Starting awk program from here, setting awk variable line to 3(line which OP wants to skip from bottom)
{
  a[NR]=[=13=]                  ##Creating array a with index of NR and value is current line.
}
END{                        ##Starting END block of this program from here.
  for(i=1;i<=NR;i++){       ##Starting for loop till value of NR here.
    if(i != (NR-line)){     ##Checking condition if i is NOT equal to NR-line then do following.
      print a[i]            ##Printing a with index i here.
    }
  }
}
' Input_file                ##Mentioning Input_file name here.

ed

ed -s ip.txt <<< $'$-2d\nw'

# thanks Shawn for a more portable solution
printf '%s\n' '$-2d' w | ed -s ip.txt

这将进行 in-place 编辑。 $ 指的是最后一行,您可以指定一个负的相对值。因此,$-2 将引用最后但第二行。 w 命令将写入更改。

有关详细信息,请参阅 ed: Line addressing

要删除文件的第 3-to-last 行,您可以使用 headtail:

{ head -n -3 file; tail -2 file; }

在输入文件很大的情况下,当性能很重要时,这非常快,因为它不会逐行读取和写入。另外,不要修改括号旁边的分号和空格,参见commands grouping.


或使用 sedtac:

tac file | sed '3d' | tac

或使用 awktac:

tac file | awk 'NR!=3' | tac

这可能适合您 (GNU sed):

sed '1N;N;$!P;D' file

打开一个 window 文件中的 3 行,然后 print/delete 打开 window 的第一行,直到文件结束。

在文件末尾,不要打印 window 中的第一行,即文件末尾的第 3 行。相反,删除它,然后重复 sed 循环。这将尝试在文件末尾后追加一行,这将导致 sed 退出,打印 window.

中的剩余行

向后 n 行(其中 n 是从文件末尾算起 2 行或更多行)的通用解决方案是:

sed ':a;N:s/[^\n]*/&/3;Ta;$!P;D' file 

当然你可以使用:

tac file | sed 3d | tac

但是你会读文件 3 次。