Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/google-maps/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 在没有临时(中间)文件的同一文件上处理_Linux_Bash_Awk_Sed - Fatal编程技术网

Linux 在没有临时(中间)文件的同一文件上处理

Linux 在没有临时(中间)文件的同一文件上处理,linux,bash,awk,sed,Linux,Bash,Awk,Sed,我正在使用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(/ +

我正在使用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$ 

还是不行。有没有一种方法可以在不涉及中间文件的情况下实现相同的目标?

您可以使用
sed-i
,而
sed
将为您处理它

例如:

sed -i 's/[ \t]*$//g' file

使用
>abc
的问题是,shell首先处理重定向,并在运行实际命令之前将文件
abc
初始化为0字节。换句话说,您的awk命令在一个空的0字节文件上运行

这里有一个技巧,您不仅可以用于此命令,还可以用于任何其他命令

f='abc'
awk '{sub(/ +$/, "")} 1' "$f" | awk -c f="$f" -v RS=$'\g' 'END{printf $0 > f}'
$'\g'
只是一个随机选择的不太可能的记录分隔符,在任何文件中都不存在,从而导致整个文件在一行中读取。诀窍是在一条记录中读取整个文件,并只在
END
部分写入输出这也适用于大文件。


早期解决方案: 您可以使用
tee

awk '{gsub(/ +$/, "")} {print $0}' abc | tee abc
如果要放弃标准输出,请使用:

awk '{gsub(/ +$/, "")} {print $0}' abc | tee abc > /dev/null

有几种可能的解决办法。但是,请确保使用大文件进行测试,在我的机器上,小于~100Ko的文件将使用以下文件:
cat abc | tee abc>/dev/null
,但当管道缓冲区已满时,问题会出现,然后发送到下一个进程。当tee收到它写入文件的第一个信息块时,cat进程将无法再从该文件中读取,这将导致数据损坏

使用Gawk4.1+您可以像sed一样使用选项(-i)。 见此帖:

如果你不能使用Gawk4.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

使用
海绵

%sed“s/root/toor/”/etc/passwd | grep-v joey |海绵/etc/passwd

例如:


我想先找到问题的根源:中间文件对您来说是个问题吗?这只是创建/复制/删除它的麻烦吗?还是别的?没什么原因,只是想保持干净。谢谢。我以前用sed看到过这种答案。但问题是,我不仅仅是在做这种手术。如果我做了一些sed不能做的更复杂的过程,但我仍然不想使用中间文件,那该怎么办?你可以编写一个小函数,它会为你做,并在需要的时候使用它。否则,没有中间文件是不可能的。对于更复杂的东西,您也可以使用perl-i。请注意,
sed-i…
仍在使用一个临时文件,它只是对您隐藏了细节。它实际上并没有进行适当的编辑——这在一般情况下是很难做到的,如果不是不可能的话。我怀疑这是否适用于非常大的文件。您可能可以使用海绵。它之所以有效,是因为您的所有测试文件都可以缓冲。如果您有一个大文件,则在通过tee写入之前无法对其进行缓冲。使用以下命令进行测试:抱歉,验证中存在轻微错误。看看这个:对不起-1。您的解决方案已损坏,不应用于生产。您可能会损坏数据。如果我理解正确,整个文件是否已加载到内存中?对于大型文件,这可能仍然是一个问题。在处理数据时写入数据对我来说似乎是最好的选择。试图用更复杂、效率更低的解决方案来避免临时文件听起来是个坏主意。“不打破鸡蛋,你就做不了煎蛋饼”。
Probably the most general purpose tool in moreutils so far is sponge(1), 
which lets you do things like this:
/tmp$ cat -E abc 
aaaaa    $
/tmp$ awk '{gsub(/ +$/, "")} {print $0}' abc | sponge abc 
/tmp$ cat -E abc 
aaaaa$