在Unix中删除倒数第二行的一个字符。

3

如何在Unix系统中删除文件的倒数第二行?

例如,我有一个文件,其内容如下:

aaa
bbb*
ccc*
ddd*
eee

我的输出应该是:
aaa
bbb*
ccc*
ddd
eee

有没有对此的想法?
5个回答

5

使用sed在单次操作中执行此操作的通用方法是使用滑动窗口,类似于GNU sed手册中描述的内容。

由于您只对倒数第二行的替换感兴趣,因此不需要保留空间。在这种情况下,只需使用一个N即可:

sed 'N; $! { P; D; }; s/.\n/\n/'

或者作为一个兼容BSD sed的脚本:
sed 'N; $! { P; D; }; s/.\n/\
/'

输出:

aaa
bbb*
ccc*
ddd
eee

解释

  • N 命令向模式空间添加第二行。
  • 当未达到最后一行时,$! 块被评估。
  • { P; D; } 打印模式空间的第一行并删除它。如果模式空间不为空,则 D 具有重新启动脚本的副作用。
  • 替换命令仅在最后两行位于模式空间时才被评估。

由于替换仅在遇到最后一行时发生,也许更积极的方法是 sed '$!N;$s/.\(\n\)/\1/;P;D' file - potong
@potong:是的,这样更明确,但对于像这样的短脚本,我更喜欢在最后运行命令。 - Thor

2

有三种常见的方法。

使用wc -l file命令获取行数:

awk 'NR==n-1{sub(/.$/,"")}1' n=$(wc -l file)
aaa
bbb*
ccc*
ddd
eee

文件需要被解析两次:

awk 'FNR==NR{n++;next}FNR==n-1{sub(/.$/,"")}1' file file
aaa
bbb*
ccc*
ddd
eee

在处理前后反转文件:

tac file | sed '2s/.$//' | tac
aaa
bbb*
ccc*
ddd
eee

2

现在是重新使用 ed 的好时机:

简短版:

{ echo '$-1s/.$//' ; echo "w" ; } | ed file_to_modify.txt >/dev/null

带有一些“调试信息”的版本 ^^ :

{ echo 'doing: $-1s/.$//' >&2 ; echo '$-1s/.$//' ; echo "doing: w" >&2 ; echo "w" ; echo "C" >&2 ; } | ed file_to_modify.txt

简而言之:ed非常接近于vi,但是一次只能在1行上操作... 我只需要告诉它“s /。$ //”(将行的最后一个字符替换为空)在第n-1行上执行($ = ed中的最后一行,“$-1” = 最后一行 - 1)。

1
vivim或任何编辑器打开文件,按照您的意愿编辑文件。

如果vim是一个选项,这个问题根本就不存在!那么如果OP需要在shell脚本中使用它呢? - Kent

0

使用awk非常直接:

awk '{a[NR]=$0}END{for(i=1;i<=NR;i++){if(i==NR-1)sub(/.$/,"",a[i]);print a[i]}}' file

使用awk有点棘手:

awk '{if(f>1)print p;p=l;f++;l=$0}END{sub(/.$/,"",p);print p;print l}' file

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接