Bash 为什么管道到同一个文件不';在某些平台上不工作?
在cygwin中,以下代码可以正常工作Bash 为什么管道到同一个文件不';在某些平台上不工作?,bash,pipeline,overwrite,io-redirection,in-place,Bash,Pipeline,Overwrite,Io Redirection,In Place,在cygwin中,以下代码可以正常工作 $ cat junk bat bat bat $ cat junk | sort -k1,1 |tr 'b' 'z' > junk $ cat junk zat zat zat 但是在linux shell(GNU/linux)中,覆盖似乎不起作用 [41] othershell: cat junk cat cat cat [42] othershell: cat junk |sort -k1,1 |tr 'c' 'z' zat zat zat
$ cat junk
bat
bat
bat
$ cat junk | sort -k1,1 |tr 'b' 'z' > junk
$ cat junk
zat
zat
zat
但是在linux shell(GNU/linux)中,覆盖似乎不起作用
[41] othershell: cat junk
cat
cat
cat
[42] othershell: cat junk |sort -k1,1 |tr 'c' 'z'
zat
zat
zat
[43] othershell: cat junk |sort -k1,1 |tr 'c' 'z' > junk
[44] othershell: cat junk
这两种环境都运行BASH
我这样问是因为有时在我进行文本处理之后,由于这个警告,我被迫创建tmp文件。但是我知道,在Perl中,您可以在一些操作/操作之后,使用“I”标志覆盖原始文件。我只是想问一下,在unix管道中是否有任何万无一失的方法来覆盖我不知道的文件。一般来说,这可能会被破坏。管道中的进程都是并行启动的,因此在管道前端的进程完成(甚至开始)读取输入文件之前,行末尾的垃圾通常会截断输入文件 即使在Cygwin领导下的bash让你逍遥法外,你也不应该依赖它。一般的解决方案是重定向到临时文件,然后在管道完成后重命名它。这里有四个要点:
{ sort -k1,1 | tr 'c' 'z'; } < junk > sorted_junk
而且,由于在海绵从管道接收EOF之前,垃圾邮件不会被覆盖,因此您将获得预期的结果。如果要编辑该文件,您可以使用编辑器
ex junk << EOF
%!(sort -k1,1 |tr 'b' 'z')
x
EOF
ex junk覆盖管道中的同一个文件不是建议,因为当你犯了错误时,你无法将其取回(除非你有备份或它处于版本控制之下)
发生这种情况是因为管道中的输入和输出是自动缓冲的(这给您一种它工作的印象),但实际上它是并行运行的。不同的平台可以以不同的方式(根据设置)缓冲输出,因此在某些平台上,您最终得到的是空文件(因为文件将在开始时创建),而在另一些平台上,您得到的是半成品文件
解决方案是,当文件仅在遇到具有完全缓冲和处理输入的EOF时才被重写时,使用某种方法
这可以通过以下方式实现:
- 使用实用程序,它可以在打开输出文件之前吸收所有输入
这可以通过
spoone
(与expect
package中的unbuffer
相反)来完成
- 避免使用I/O重定向语法(这会在启动命令之前创建空文件)
例如,使用
tee
(缓冲其标准流),例如:
cat junk | sort | tee junk
这只适用于排序
,因为它需要所有输入来处理排序。因此,如果您的命令没有使用排序
,请添加一个
另一个可以使用的工具是stdbuf
,它修改其标准流的缓冲操作,您可以在其中指定缓冲区大小
- 使用可就地编辑文件的文本处理器(如
sed
或ex
)
例如:
$ ex -s +'%!sort -k1' -cxa myfile.txt
$ sed -i '' s/foo/bar/g myfile.txt
使用以下简单脚本,您可以使其按照您的意愿工作:
$ cat junk | sort -k1,1 |tr 'b' 'z' | overwrite_file.sh junk
覆盖_file.sh
请注意,如果您不想将更新后的文件发送到stdout,可以使用这种方法
覆盖文件\u no\u output.sh
Perl和sed的-i
在幕后执行临时文件操作。请参阅,感谢您深思熟虑的回答!我改变了输入,只是为了把问题弄清楚。需要对原始输入进行排序。但你是对的。在本例中,sort不起任何作用海绵
就像猫
@nobar一样,它们是不同的。请参阅软件包中的内容。@CodeGnome:很抱歉,我不打算发布这些内容。这只是我从未完成的一句话的开头。相反,我写了一篇关于海绵的使用说明。
$ ex -s +'%!sort -k1' -cxa myfile.txt
$ sed -i '' s/foo/bar/g myfile.txt
$ cat junk | sort -k1,1 |tr 'b' 'z' | overwrite_file.sh junk
#!/usr/bin/env bash
OUT=$(cat -)
FILENAME="$*"
echo "$OUT" | tee "$FILENAME"
#!/usr/bin/env bash
OUT=$(cat -)
FILENAME="$*"
echo "$OUT" > "$FILENAME"