假设我有一个任意的多行文本文件:
sometext
moretext
lastline
我怎样才能删除文件中仅有的最后一个字符(不是换行或null)而不使文本文件失效?
sed '$ s/.$//' somefile
$
是一个 Sed 地址,仅匹配最后一行输入,因此只会在最后一行上执行以下函数调用 (s/.$//
)。
s/.$//
将(在这种情况下是最后)行上的最后一个字符替换为空字符串;即有效地删除行上的最后一个字符(换行符之前)。
.
匹配行上的任何字符,并在其后加上$
将匹配锚定到行的末尾;请注意,此正则表达式中的$
的使用在概念上与之前作为 Sed 地址使用的$
相关,但在技术上是不同的。
sed -i '$ s/.$//' somefile
注意:
-i ''
而不是只使用 -i
;有关与 -i
相关的陷阱的概述,请参阅 this answer 的下半部分。截断
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取的是最后一个字节(而不是字符)。
即使处理大文件也几乎不需要时间。
为什么不用sed
使用类似sed '$ s/.$//' file
的sed解决方案的问题在于它首先读取整个文件(处理大文件需要很长时间),然后你需要一个临时文件(与原始文件大小相同):
sed '$ s/.$//' file > tempfile
rm file; mv tempfile file
然后将临时文件移动以替换该文件。
brew install truncate
,然后再执行 truncate -s -1 file
。 - dux2ex
的示例,我认为它不像sed解决方案那样神秘。 printf '%s\n' '$' 's/.$//' wq | ex somefile
$
移到最后一行,s
删除最后一个字符,wq
是众所周知(对于vi用户)的写入+退出。在尝试了各种不同的策略(并避免使用sed -i或perl)之后,我发现最好的方法是:
sed '$! { P; D; }; s/.$//' somefile
sed -i
。这只是一个将数据写回文件的函数。现在你只能在监视器上获得输出。 - Jotneawk
应该可以做到:awk '{a[NR]=$0} END {for (i=1;i<NR;i++) print a[i];sub(/.$/,"",a[NR]);print a[NR]}' file
sometext
moretext
lastlin
awk -i 'your code' file
。 - Jotne仅供参考:sed将暂时删除文件。因此,如果您正在追踪该文件,则会收到“无此文件或目录”的警告,直到重新发出tail命令。
编辑后的答案
我创建了一个脚本,并将您的文本放在桌面上。这个测试文件保存为“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'
sometext
moretext
lastlin
我为之前的回答道歉(没有仔细阅读)
sed 's/.$//' 文件名 | tee 新文件名
这应该能完成你的任务。