Tod*_*ly' 154 linux shell perl awk sed
我有一些文件,如果它是文件中的最后一个字符,我想删除最后一个换行符. od -c告诉我,我运行的命令确实用一个尾随的新行写了一个文件:
0013600 n t > \n
Run Code Online (Sandbox Code Playgroud)
我已经尝试了一些与sed的技巧,但我能想到的最好的不是诀窍:
sed -e '$s/\(.*\)\n$/\1/' abc
Run Code Online (Sandbox Code Playgroud)
任何想法如何做到这一点?
pav*_*ium 213
perl -pe 'chomp if eof' filename >filename2
Run Code Online (Sandbox Code Playgroud)
或者,编辑文件:
perl -pi -e 'chomp if eof' filename
Run Code Online (Sandbox Code Playgroud)
[编者注:-pi -e最初是-pie,但正如几位评论者所指出并由@hvd解释,后者不起作用.]
这在我看到的awk网站上被描述为"perl blasphemy".
但是,在测试中,它起作用了.
mkl*_*nt0 54
您可以利用shell 命令替换删除尾随换行符的事实:
在bash,ksh,zsh中工作的简单形式:
printf %s "$(< in.txt)" > out.txt
Run Code Online (Sandbox Code Playgroud)
便携式(POSIX兼容)替代方案(效率略低):
printf %s "$(cat in.txt)" > out.txt
Run Code Online (Sandbox Code Playgroud)
注意:
in.txt以多个换行符结尾,命令替换将删除所有这些 - 谢谢,@ Sparhawk.(除了尾随换行符之外,它不会删除空白字符.)printf %s确保输出不附加换行符(它是符合POSIX标准的非标准替代品echo -n;请参阅http://pubs.opengroup.org/onlinepubs/009696799/utilities/echo.html和https://unix.stackexchange. com/a/65819)一个人工引导到另一个答案:
如果Perl可用,请选择接受的答案 - 它简单且内存效率高(不会立即读取整个输入文件).
否则,考虑一下ghostdog74的Awk答案 - 它模糊不清,而且内存效率高 ; 一个更可读的等效(POSIX标准)为:
awk 'NR > 1 { print prev } { prev=$0 } END { ORS=""; print }' in.txtEND块中处理,\n由于将输出记录separator(OFS)设置为空字符串,因此打印时没有尾随.如果你想要一个简单但快速而强大的解决方案,它可以就地编辑(而不是创建一个替换原始文件的临时文件),请考虑使用jrockway的Perl脚本.
Tho*_*hor 45
您可以使用headGNU coreutils 执行此操作,它支持相对于文件末尾的参数.所以要留下最后一个字节使用:
head -c -1
Run Code Online (Sandbox Code Playgroud)
要测试结束换行符,您可以使用tail和wc.以下示例将结果保存到临时文件,然后覆盖原始文件:
if [[ $(tail -c1 file | wc -l) == 1 ]]; then
head -c -1 file > file.tmp
mv file.tmp file
fi
Run Code Online (Sandbox Code Playgroud)
您还可以使用spongefrom moreutils进行"就地"编辑:
[[ $(tail -c1 file | wc -l) == 1 ]] && head -c -1 file | sponge file
Run Code Online (Sandbox Code Playgroud)
您还可以通过将其填充到.bashrc文件中来制作一般的可重用函数:
# Example: remove-last-newline < multiline.txt
function remove-last-newline(){
local file=$(mktemp)
cat > $file
if [[ $(tail -c1 $file | wc -l) == 1 ]]; then
head -c -1 $file > $file.tmp
mv $file.tmp $file
fi
cat $file
}
Run Code Online (Sandbox Code Playgroud)
正如KarlWilbur在评论中所指出并用于Sorentar的回答,truncate --size=-1可以替换head -c-1并支持就地编辑.
Pau*_*ce. 16
head -n -1 abc > newfile
tail -n 1 abc | tr -d '\n' >> newfile
Run Code Online (Sandbox Code Playgroud)
编辑2:
这是一个awk版本(已更正),不会累积一个潜在的巨大数组:
awk'{if(line)print line; line = $ 0} END {printf $ 0}'abc
gho*_*g74 10
呆子
awk '{q=p;p=$0}NR>1{print q}END{ORS = ""; print p}' file
Run Code Online (Sandbox Code Playgroud)
一个快速的解决方案是使用 gnu 实用程序truncate:
[ -z $(tail -c1 file) ] && truncate -s-1 file
Run Code Online (Sandbox Code Playgroud)
如果文件有尾随换行符,则测试为真。
删除非常快,真正到位,不需要新文件,搜索也是从末尾读取一个字节 ( tail -c1)。
如果你想做得对,你需要这样的东西:
use autodie qw(open sysseek sysread truncate);
my $file = shift;
open my $fh, '+>>', $file;
my $pos = tell $fh;
sysseek $fh, $pos - 1, 0;
sysread $fh, my $buf, 1 or die 'No data to read?';
if($buf eq "\n"){
truncate $fh, $pos - 1;
}
Run Code Online (Sandbox Code Playgroud)
我们打开文件进行阅读和追加; 打开附加意味着我们已经seek编辑到文件的末尾.然后我们得到文件末尾的数字位置tell.我们使用该数字来寻找一个字符,然后我们读取一个字符.如果是换行符,我们会在该换行符之前将文件截断为字符,否则,我们什么都不做.
对于任何输入,它都以恒定的时间和恒定的空间运行,并且不需要任何更多的磁盘空间.
小智 8
单行文件的一种非常简单的方法,需要来自coreutils的GNU echo:
/bin/echo -n $(cat $file)
Run Code Online (Sandbox Code Playgroud)
这是一个漂亮,整洁的Python解决方案.我没有试图在这里简洁.
这会就地修改文件,而不是复制文件并从副本的最后一行剥离换行符.如果文件很大,这将比选择作为最佳答案的Perl解决方案快得多.
如果最后两个字节是CR/LF,它会将文件截断两个字节,如果最后一个字节是LF,则截断一个字节.如果最后一个字节不是(CR)LF,它不会尝试修改文件.它处理错误.在Python 2.6中测试过.
把它放在一个名为"striplast"的文件中chmod +x striplast.
#!/usr/bin/python
# strip newline from last line of a file
import sys
def trunc(filename, new_len):
try:
# open with mode "append" so we have permission to modify
# cannot open with mode "write" because that clobbers the file!
f = open(filename, "ab")
f.truncate(new_len)
f.close()
except IOError:
print "cannot write to file:", filename
sys.exit(2)
# get input argument
if len(sys.argv) == 2:
filename = sys.argv[1]
else:
filename = "--help" # wrong number of arguments so print help
if filename == "--help" or filename == "-h" or filename == "/?":
print "Usage: %s <filename>" % sys.argv[0]
print "Strips a newline off the last line of a file."
sys.exit(1)
try:
# must have mode "b" (binary) to allow f.seek() with negative offset
f = open(filename, "rb")
except IOError:
print "file does not exist:", filename
sys.exit(2)
SEEK_EOF = 2
f.seek(-2, SEEK_EOF) # seek to two bytes before end of file
end_pos = f.tell()
line = f.read()
f.close()
if line.endswith("\r\n"):
trunc(filename, end_pos)
elif line.endswith("\n"):
trunc(filename, end_pos + 1)
Run Code Online (Sandbox Code Playgroud)
PS本着"Perl高尔夫"的精神,这是我最短的Python解决方案.它将整个文件从标准输入篡改到内存中,从最后删除所有换行符,并将结果写入标准输出.不像Perl那样简洁; 你只是无法击败Perl这样的小巧琐事.
从调用中删除"\n" .rstrip(),它将从文件末尾删除所有空格,包括多个空行.
把它放入"slurp_and_chomp.py"然后运行python slurp_and_chomp.py < inputfile > outputfile.
import sys
sys.stdout.write(sys.stdin.read().rstrip("\n"))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
97398 次 |
| 最近记录: |