如何在unix中删除文件的最后一个字符?

Max*_*rty 58 unix linux bash sed

说我有一些任意的多行文本文件:

sometext
moretext
lastline
Run Code Online (Sandbox Code Playgroud)

如何在不使文本文件无效的情况下仅删除文件的最后一个字符(e,而不是换行符或null)?

mkl*_*nt0 73

一种更简单的方法(输出到stdout,不更新输入文件):

sed '$ s/.$//' somefile
Run Code Online (Sandbox Code Playgroud)
  • $是仅与最后一个输入行匹配的Sed地址,因此导致以下函数call(s/.$//)仅在最后一行执行.
  • s/.$//用空字符串替换(在本例中为last)行的最后一个字符; 即,有效地删除最后一个字符.(换行前)上线.
    .匹配该行上的任何字符,并使用$锚点跟随该行匹配到该行的末尾; 请注意$在此正则表达式中的使用在概念上是如何相关的,但在技术上与先前使用的$Sed 地址不同.
  • 使用stdin输入的示例(假设Bash,Ksh或Zsh):

    $ sed '$ s/.$//' <<< $'line one\nline two'
    line one
    line tw
    
    Run Code Online (Sandbox Code Playgroud)

更新输入文件(如果输入文件是符号链接,请不要使用):

sed -i '$ s/.$//' somefile
Run Code Online (Sandbox Code Playgroud)

注意:
*在OSX上,你必须使用-i ''而不是仅仅-i; 有关相关陷阱的概述-i,请参阅我的答案的下半部分.
*如果您需要处理非常大的输入文件和/或性能/磁盘使用是一个问题,并且您正在使用GNU实用程序(Linux),请参阅sorontar的有用答案.


sor*_*tar 40

truncate

truncate -s-1 file
Run Code Online (Sandbox Code Playgroud)

从同一文件的末尾删除一个(-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
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为tail占用了最后一个字节(不是char).

即使使用大文件也几乎没有时间.

为什么不 sed

像sed解决方案的问题sed '$ s/.$//' file是它首先读取整个文件(花费很长时间使用大文件),然后你需要一个临时文件(与原始文件大小相同):

sed '$ s/.$//' file  > tempfile
rm file; mv tempfile file
Run Code Online (Sandbox Code Playgroud)

然后移动临时文件以替换该文件.