使用 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
的解决方案,请你试试下面的方法。只需将 awk
的 line
变量设置为你想跳过的行(从底部开始)。
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 行,您可以使用 head
和 tail
:
{ head -n -3 file; tail -2 file; }
在输入文件很大的情况下,当性能很重要时,这非常快,因为它不会逐行读取和写入。另外,不要修改括号旁边的分号和空格,参见commands grouping.
或使用 sed
和 tac
:
tac file | sed '3d' | tac
或使用 awk
和 tac
:
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 次。
我有几个行号不同的文本文件,我必须删除所有文件中的倒数第三行。这是一个示例文件:
bear
horse
window
potato
berry
cup
此文件的预期结果:
bear
horse
window
berry
cup
我们可以删除文件的倒数第三行吗:
一种。不基于任何 string/pattern.
b.仅基于必须是倒数第三行的条件
我对如何从最后一行开始索引我的文件有疑问。我已经从倒数第二行的另一个 SO 问题中尝试了这个:
> sed -i 'N;$!P;D' output1.txt
有了tac
+ awk
的解决方案,请你试试下面的方法。只需将 awk
的 line
变量设置为你想跳过的行(从底部开始)。
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 行,您可以使用 head
和 tail
:
{ head -n -3 file; tail -2 file; }
在输入文件很大的情况下,当性能很重要时,这非常快,因为它不会逐行读取和写入。另外,不要修改括号旁边的分号和空格,参见commands grouping.
或使用 sed
和 tac
:
tac file | sed '3d' | tac
或使用 awk
和 tac
:
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 次。