bash脚本:在输出也是输入的情况下连接两个文件的安全方法?
如果我有两个文件bash脚本:在输出也是输入的情况下连接两个文件的安全方法?,bash,file,concatenation,Bash,File,Concatenation,如果我有两个文件file1,file2,我可以在bash中以安全的方式将它们关联起来,使file1或file2中的一个既是输出文件又是输入文件吗 例如: $ cat file1 file2 >> file2 $ printf 'one\ntwo\n' >foo $ printf 'three\nfour\n' >bar $ sed -i '' '$rbar' foo $ cat foo one two three four 产生: $ cat: file2: inpu
file1
,file2
,我可以在bash中以安全的方式将它们关联起来,使file1
或file2
中的一个既是输出文件又是输入文件吗
例如:
$ cat file1 file2 >> file2
$ printf 'one\ntwo\n' >foo
$ printf 'three\nfour\n' >bar
$ sed -i '' '$rbar' foo
$ cat foo
one
two
three
four
产生:
$ cat: file2: input file is output file
我想这意味着我所做的不是“安全的”
这也让我感到惊讶-在>
操作符之后,cat如何知道文件2
。这里的第二个问题是>
如何在bash中工作?在将数据“重定向/保存”到操作员后面的文件之前,它是否将数据存储在临时位置
~$ echo hello > f1
~$ echo world > f2
使用tmp文件:
~$ cat f1 f2 > tmp && cat tmp >> f1 && rm tmp
~$ cat f1
hello
hello
world
使用tee-a:
~$ cat f1 f2 | tee -a f1
hello
world
~$ cat f1
hello
hello
world
使用粘贴:
~$ paste -d"\n" f1 f2 >> f1
~$ cat f1
hello
hello
world
使用bash的printf:
$ printf "%s\n%s\n" "$(<f1)" "$(<f2)" >> f1
$ cat f1
hello
hello
world
$printf“%s\n%s\n”“$”(正确的解决方案是使用临时文件
使用临时文件的一种方法是使用不可见的工具。sed
,例如:
$ cat file1 file2 >> file2
$ printf 'one\ntwo\n' >foo
$ printf 'three\nfour\n' >bar
$ sed -i '' '$rbar' foo
$ cat foo
one
two
three
four
或者,模仿您在第一个示例中尝试的操作:
$ printf 'one\ntwo\n' >foo
$ printf 'three\nfour\n' >bar
$ sed -i '' -e '$rbar' -e '$rbar' foo
$ cat foo
one
two
three
four
three
four
当然,您可以调整操作系统的sed选项。解决方法
以下内容可安全解决您的问题:
cat file1 <(dd if=file2 bs="$(wc -c <file2)" count=1) >> file2
cat文件1>file2
解释
如果cat
在这里没有保护措施(有些实现没有!),您将有一个无休止的循环-文件2
中将永远有更多的信息(因为cat
自己的输出被附加到它),因此附加操作将永远不会停止
dd if=file2 bs=SIZE\u OF_file2 count=1
仅在命令启动时发出file2
中存在的字节数,因此它避免了这种无休止的循环。此外,由于cat
正在从进程替换中读取,因此它无法检测到file2
是内容的源,所以它会这样做esn不会触发错误。使用临时文件:
tmp=$(mktemp)
cat f2 f1 f2 > "$tmp" &&
ln -f "$tmp" f2 &&
rm "$tmp"
您不能附加到正在读取的文件。输出到第三个文件,然后将第三个文件mv
添加到第二个文件。>
不会写入缓冲区;它会写入一个文件,因此需要一个新文件来转储cat
输出。Linux都是基于文件的。如果您想安装,可以从moreutils包获得帮助l一个附加包。外壳在启动cat
之前打开file2
进行输出,但是cat
完全能够检查其标准输出并告诉(1)它是否是文件,以及(2)它是哪个文件。@glennjackman,即使存在海绵-a
,但如果我们谈论的是一个大文件,它的操作成本要高得多,因为它从一开始就重写输出文件,而不是只从附加点写入。OP使用的是
,而不是
。因此没有截断操作。这就是说--我认为你把它误认为是OP错误的一个更常见的变体。你最好引用”$(这适用于短文件。如果我们处理的是兆字节或千兆字节…我还没有测试过,但该命令行真的能工作吗?在我的系统上,wc-c file2
包含文件名。关于无休止循环的观点很好。作为参考,你可以“欺骗”猫(为了科学!)通过在子shell中运行它,使其最终输出不可检测:(cat foo bar)>bar
。在我的测试中,这产生了一个bar
,其中包含foo
的重复内容,没有原始bar
@ghoti的迹象,….我很惊讶它能起作用——给定的重定向是在调用cat
的shell启动之前执行的,而不是在shell启动之前执行的cat
,对从cat
的启动中内省传递到stdout上的文件描述符的检测过程没有任何影响(我希望如此)。您确定您是在一个首先可以进行检测的平台上进行测试的吗?(例如,在MacOS的cat
中不可用)@ghoti,…并在MacOS上运行GNUcat
,检测似乎仍然有效:$(gcat file1 file2)>>file2
在gcat:file2:input file is output file
@ghoti,…现在,什么可以绕过检测(但可能会产生一个无休止的输出文件,这取决于file2的大小和竞争的结果)是cat file1>file2
。