说我有一些任意的多行文本文件:
sometext moretext lastline
我怎样才能删除文件的最后一个字符(e,而不是换行符或空),而不使文本文件无效?
一个更简单的方法( 输出到标准输出 ,不更新输入文件):
sed '$ s/.$//' somefile
$
是一个Sed地址,它只与最后一行相匹配,因此在最后一行上执行下面的函数调用( s/.$//
)。 s/.$//
用一个空字符串替换(在这种情况下是最后一行)的最后一个字符; 即有效地去除最后一个字符。 (换行之前)就行了。 .
匹配该行上的任何字符,并用$
将该匹配锚定到该行的末尾; 注意这个正则表达式中$
的使用是如何在概念上相关的,但是在技术上与前面使用$
作为Sed 地址不同 。 使用stdin输入的示例(假定为Bash,Ksh或Zsh):
$ sed '$ s/.$//' <<< $'line one\nline two' line one line tw
也要更新输入文件 (如果输入文件是符号链接,请不要使用):
sed -i '$ s/.$//' somefile
注意:
*在OSX上,您必须使用-i ''
而不是仅仅-i
; 有关与-i
相关的陷阱的概述,请参阅我的答案的下半部分。
*如果您需要处理非常大的输入文件和/或性能/磁盘使用情况, 并且您正在使用GNU实用程序(Linux),请参阅sorontar的有用答案 。
truncate
truncate -s-1 file
从同一个文件的末尾删除一个(-1)字符。 正如一个>>
会附加到同一个文件中。
这种方法的问题是,如果它存在,它不保留一个尾随的换行符。
解决方案是:
if [ -n "$(tail -c1 file)" ] # if the file has not a trailing new line. then truncate -s-1 file # remove one char as the question request. else truncate -s-2 file # remove the last two characters echo "" >> file # add the trailing new line back fi
这工作,因为尾部采取最后一个字节(不是字符)。
即使是大文件也几乎没有时间。
为什么不sed
像sed '$ s/.$//' file
这样的sed解决方案的问题是,它首先读取整个文件(花费很长时间处理大文件),那么您需要一个临时文件(与原文件大小相同):
sed '$ s/.$//' file > tempfile rm file; mv tempfile file
然后移动tempfile来替换文件。
这是另一个使用ex
,我觉得不像sed解决方案神秘:
printf '%s\n' '$' 's/.$//' wq | ex somefile
$
到最后一行, s
删除最后一个字符, wq
是众所周知的(vi用户)write + quit。
在玩了很多不同的策略(并避免sed -i或perl)之后,我发现这样做的最好方法是:
sed '$! { P; D; }; s/.$//' somefile
如果目标是删除最后一行中的最后一个字符,那么awk
应该这样做:
awk '{a[NR]=$0} END {for (i=1;i<NR;i++) print a[i];sub(/.$/,"",a[NR]);print a[NR]}' file sometext moretext lastlin
它将所有数据存储到数组中,然后将其打印出来并更改最后一行。
编辑答案
我创建了一个脚本,并将您的文本放在我的桌面上。 这个测试文件保存为“old_file.txt”
sometext moretext lastline
之后,我写了一个小脚本来取出旧文件,并删除最后一行中的最后一个字符
#!/bin/bash no_of_new_line_characters=`wc '/root/Desktop/old_file.txt'|cut -d ' ' -f2` let "no_of_lines=no_of_new_line_characters+1" sed -n 1,"$no_of_new_line_characters"p '/root/Desktop/old_file.txt' > '/root/Desktop/my_new_file' sed -n "$no_of_lines","$no_of_lines"p '/root/Desktop/old_file.txt'|sed 's/.$//g' >> '/root/Desktop/my_new_file'
打开我创建的new_file,显示如下输出:
sometext moretext lastlin
我对之前的回答表示歉意(没有仔细阅读)
只是一句话:sed会暂时删除文件。 所以,如果你拖尾文件,你会得到一个“没有这样的文件或目录”警告,直到你重新发出tail命令。
sed 's/.$//' filename | tee newFilename
这应该做你的工作。