如何替换最后一个非空行中的文本?

如何替换最后一个非空行中的文本?

我想找到文件中的最后一行文本,并删除其末尾的逗号。我已经问过这个问题了,但是,在我得到答案后,我意识到我的问题不够具体。

sed命令将转到文件的最后一行并对其执行操作。就我而言,我想删除结尾的逗号:

sed -i '$ s/",/"/g' file.txt

所以这:

blah blah blah,
blah blah blah,
blah blah blah,

...变成这样:

blah blah blah,
blah blah blah,
blah blah blah

然而,如果最后一行文本后面有空行,这将不起作用在文件中。

我一直在寻找获取最后一行文本的方法,但还没有想出任何我可以理解和应用的方法。我还寻找了删除所有尾随空白行的方法,并找到了以下命令:

sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' *.txt

但它对我不起作用(它似乎只是在命令行上输出我的文件的内容)。无论如何,这都是不优雅的。我不想删除尾随的空白行,最好只识别最后一行包含文本的内容并对其采取行动。

如何删除最后一行的逗号文本的在一个目录的多个文件中?

答案1

对于大文件,使用 Guru 的答案,速度更快。然而,在小文件(<25 行)上,我发现这稍微快一些(假设您有 GNU tac):

tac file | awk '!/^[[:blank:]]*$/{i++;if(i==1){sub(",$","")}}1' | tac

答案2

回答

perl -0777 -p -i -e 's/,(\n*)\Z/\1/m' *.txt

将删除所有以 结尾的文件中的最后一个 ',' .txt,如果 ',' 后面仅跟有 0 个或多个换行符,然后是文件末尾。

从你的例子来看:

reedm@www:~/tmp $ cat > test.txt
blah blah blah,
blah blah blah,
blah blah blah,


reedm@www:~/tmp $ perl -0777 -p -i -e 's/,(\n*)\Z/\1/m' *.txt
reedm@www:~/tmp $ cat test.txt
blah blah blah,
blah blah blah,
blah blah blah


reedm@www:~/tmp $ 

瓦?

即使在最好的情况下,Perl 也是一头深奥的野兽,而 Perl 的俏皮话可能特别神秘。

-e标志允许我们在命令行上传递 perl 程序。在本例中,“s/regex/replace/flags”就是程序。

-p标志使 perl 在循环中对-0所提供的每个文件名的每个“行”(请参阅​​ 参考资料)应用您提供的程序。

-i标志使 perl 用程序的输出替换文件,而不是将输出打印到标准输出。

-0标志更改 perl 用于将文件分成“行”的分隔符。0777是一个特殊值,按照惯例使用它使 perl 将整个文件读取到单个“行”中。

由于使用了一些特定于 Perl 的技巧,正则表达式有些复杂:

  • 首先,m末尾的标志导致正则表达式在多行上运行。
  • ,很简单,并且匹配单个逗号。
  • (\n*)匹配一行中的 0 个或多个换行符,并将它们存储为子模式(()字符表示子模式)。由于这是第一个子模式,我们可以\1在替换部分中使用它来表示“无论该子模式匹配什么”。
  • \Z是 Perl 特定的扩展名,并且匹配正在使用的字符串的结尾——在本例中,这是整个文件。
  • 在替换部分中,我们\1仅用一系列换行符替换匹配项,并删除逗号。

有关 perl 正则表达式和 perl 命令行标志的 man 信息,请分别查看perlre和的手册页perlrun

答案3

如果 Perl 解决方案适合您:

 perl -00pe 's/(.*),/$1/s' file

要将更改保存在文件本身中:

perl -i -00pe 's/(.*),/$1/s' file

要将其应用于多个文件:

perl -i -00pe 's/(.*),/$1/s' *.txt

答案4

sed可以进入多行搜索和替换模式,以便它可以将整个文件内容作为“模式空间”中的单行进行处理。

(注意:FreeBSDsed需要选项序列-n -i -e才能正确进行就地文件编辑。)

# delete the last , in the last non-empty line of a file
# cf. http://austinmatzko.com/2008/04/26/sed-multi-line-search-and-replace/

cat -n testfile

sed -n -i -e '
# if the first line copy the pattern to the hold buffer
1h
# if not the first line then append the pattern to the hold buffer
1!H
# if the last line then ...
$ {
# copy from the hold to the pattern buffer
g
# remove last , in last non-empty line of file 
#s/,\([^,[:cntrl:]]*\n*\)$/\1/
s/,\([^,]*\)$/\1/
p
}' testfile

相关内容