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


73

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

sometext
moretext
lastline

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


您为解决这个问题做了什么?-1
Jotne 2014年

4
列出一堆垃圾sed和awk命令,将每行的最后一个字符都剥离掉,这并没有令人感到十分建设性。嘿,知道我要为此而死。尽管如此,仍然无法离开自己的句子“我尝试了一堆sed和awk,但是只能以各种方式去除每一行的最后一个字符”。
2014年

Answers:


97

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

sed '$ s/.$//' somefile
  • $是仅与最后输入行匹配的Sed地址,因此导致s/.$//仅在最后一行执行以下函数调用()。
  • s/.$//用空字符串替换(在本例中为last)行的最后一个字符;即,有效地删除最后一个字符。(在换行符之前)。
    .匹配该行上的任何字符,并在其后跟$将匹配项锚定到该行的末尾;请注意,$在此正则表达式中的使用在概念上是相关的,但在技术上与先前将其$用作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的有用答案


56

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

之所以有效,是因为tail占用了最后一个字节(不是char)。

即使是大文件,也几乎不需要时间。

为什么不 sed

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

sed '$ s/.$//' file  > tempfile
rm file; mv tempfile file

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


4

这是另一个using ex,我发现它不像sed解决方案一样神秘:

 printf '%s\n' '$' 's/.$//' wq | ex somefile

$进入到最后一行时,s删除最后一个字符,并wq是众所周知的(至第六用户)写+退出。


2

经过一堆种不同的策略(并避免使用sed -i或perl),我发现最好的方法是:

sed '$! { P; D; }; s/.$//' somefile

1
不知道为什么要避免sed -i。这只是将数据写回到文件的功能。现在,您只需要监视输出。
乔特尼2014年

2

如果目标是删除最后一行中的最后一个字符,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

它将所有数据存储到一个数组中,然后将其打印出来并更改最后一行。


我没有运气试图>到同一文件。建议输出到新文件,删除旧文件,然后根据需要更改文件名。
MayTheSForceBeWithYou

@MayTheSForceBeWithYou Gnu Awk 4.1和更高版本进行了内联编辑,因此请尝试awk -i 'your code' file
Jotne

1

编辑答案

我创建了一个脚本,并将您的文本放在桌面上。该测试文件另存为“ 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

对于以前的回答,我深表歉意(没有仔细阅读)


1
它要求仅删除文件的最后一个字符,而不删除每行的最后一个字符。
罗宾·许

1
抱歉,我的回答不正确。.我能够使用自己创建的小脚本来获取解决方案。希望这对MaxPRafferty有帮助-repzero 2014
56

1

请注意:sed将暂时删除该文件。因此,如果要拖尾文件,则在重新发出tail命令之前,将收到“没有这样的文件或目录”警告。


0

sed 's/.$//' filename | tee newFilename

这应该做你的工作。


3
这将删除每行的最后一个字符,而不仅仅是最后一行的最后一个字符。
MaxPRafferty

@MaxPRafferty我不好。我以为问题是要删除每行的最后一个字符
karthik339,2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.