我正在使用awk对文件进行一些文本处理。例如,删除尾随空格。
awk '{gsub(/ +$/, "")} {print $0}' filename
这很好用。但是当我将输出重定向到原始文件时。它变成一个空文件。
temp$ awk '{gsub(/ +$/, "")} {print $0}' abc > abc
temp$ cat abc
temp$
所以我尝试了另一种方式。使用cat和pipe而不是awk的输入参数。
temp$ cat abc | awk '{gsub(/ +$/, "")} {print $0}' abc > abc
temp$ cat abc
temp$
仍然无效。有没有办法在不涉及中间文件的情况下实现相同的目标?
答案 0 :(得分:2)
您可以使用sed -i
而sed
会为您处理
示例:
sed -i 's/[ \t]*$//g' file
答案 1 :(得分:1)
使用> abc
的问题是shell首先处理重定向并在运行实际命令之前将文件abc
初始化为0字节 。换句话说,你的awk命令是在一个空的0字节文件上运行的。
这是一个不仅可以用于此命令而且可以用于任何其他命令的技巧。
f='abc'
awk '{sub(/ +$/, "")} 1' "$f" | awk -c f="$f" -v RS=$'\g' 'END{printf $0 > f}'
$'\g'
只是一个随机选择的不可能的记录分隔符,它会在任何文件中永远不存在,导致整行文件在一行中被读取。 Trick是在一个记录中读取整个文件,只在END
部分写入输出。 这也适用于大尺寸文件。
早期解决方案:
您可以使用tee
:
awk '{gsub(/ +$/, "")} {print $0}' abc | tee abc
如果要在stdout上丢弃输出,请使用:
awk '{gsub(/ +$/, "")} {print $0}' abc | tee abc > /dev/null
答案 2 :(得分:1)
有几种可能的解决方案。但是请使用大文件进行测试,在我的机器上,小于~100Ko的文件将使用此文件:cat abc | tee abc > /dev/null
但是当管道缓冲区已满并且随后被发送到下一个进程时会出现问题。当tee收到它写入文件的第一大块信息时,cat进程就无法从该文件中读取,这会导致数据损坏。
使用gawk 4.1+你可以选择inplace(-i)和sed一样。 看这篇文章: awk save modifications in place
如果你不能使用gawk 4.1,你仍然可以像其他人所建议的那样转换为sed inplace表达式。
否则,为了保持单线,您可以使用海绵(moreutils的一部分)重定向到相同的文件:
$ yes testing | head -n10000000 > /tmp/test
$ du /tmp/test
77M /tmp/test
$ cat /tmp/test | sponge /tmp/test
$ du /tmp/test
77M /tmp/test
如果您无法安装moreutils
使用海绵,我建议使用简单的临时文件,然后移动文件:
$ tmp=$(mktemp)
$ echo $tmp
/tmp/tmp.Tl0v8HmdaA
$ awk '{gsub(/ +$/, "")} {print $0}' abc > $tmp
$ mv $tmp abc
答案 3 :(得分:1)
sponge
Probably the most general purpose tool in moreutils so far is sponge(1), which lets you do things like this:
% sed "s/root/toor/" /etc/passwd | grep -v joey | sponge /etc/passwd
<强> e.g: 强>
/tmp$ cat -E abc
aaaaa $
/tmp$ awk '{gsub(/ +$/, "")} {print $0}' abc | sponge abc
/tmp$ cat -E abc
aaaaa$