bash将文件inputredirect到同一个文件中

基本上我想从文件中作为input文本,从该文件中删除一行,并将输出发送回相同的文件。 如果这使得它更清楚的话,这些东西。

grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > file_name 

但是,当我这样做时,我最终会得到一个空白文件。 有什么想法吗?

你不能这样做,因为bash首先处理redirect,然后执行命令。 所以在grep看file_name的时候,它已经是空的了。 你可以使用临时文件。

 grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > tmpfile cat tmpfile > file_name 

像这样,考虑使用mktemp来创buildtmpfile,但是请注意,它不是POSIX。

使用海绵来完成这种任务。 它是moreutils的一部分。

试试这个命令:

  grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | sponge file_name 

改用sed:

 sed -i '/seg[0-9]\{1,\}\.[0-9]\{1\}/d' file_name 

试试这个简单的

 grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | tee file_name 

这个时候你的文件不会是空白的:)而且你的输出也被打印到你的terminal上。

您不能使用redirect操作符( >>> )来访问同一个文件,因为它具有更高的优先级,并且会在调用该命令之前创build/截断文件。 为了避免这种情况,你应该使用适当的工具,例如teespongesed -i或其他可以将结果写入文件的工具(例如sort file -o file )。

基本上将inputredirect到同一个原始文件是没有意义的,您应该使用适当的就地编辑器,例如Ex编辑器(Vim的一部分):

 ex '+g/seg[0-9]\{1,\}\.[0-9]\{1\}/d' -scwq file_name 

哪里:

  • '+cmd' / -c – 运行任何Ex / Vim命令
  • g/pattern/d – 使用global删除与模式匹配的行( help :g
  • -s – 静音模式( man ex
  • -c wq – 执行:write:quit命令

你可以使用sed来达到同样的效果(正如其他答案中已经显示的那样),然而in-place-i )是非标准的FreeBSD扩展(在Unix / Linux上可能有不同的工作方式),基本上它编写的,而不是一个文件编辑器。 请参阅: Ex模式是否有实际用途?

还有ed (作为sed -i的替代):

 # cf. http://wiki.bash-hackers.org/howto/edit-ed printf '%s\n' H 'g/seg[0-9]\{1,\}\.[0-9]\{1\}/d' wq | ed -s file_name 

一个class轮替代scheme – 将文件的内容设置为variables:

 VAR=`cat file_name`; echo "$VAR"|grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' > file_name 

你可以用POSIX Awk使用slurp:

 !/seg[0-9]\{1,\}\.[0-9]\{1\}/ { q = q ? q RS $0 : $0 } END { print q > ARGV[1] } 

你可以用stream程replace来做到这一点。

虽然bash可以asynchronous打开所有的pipe道,但是我们必须解决这个问题。

在你的例子中:

 grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > >(sleep 1 && cat > file_name) 
  • >(sleep 1 && cat > file_name)创build一个临时文件,从grep接收输出
  • sleep 1秒延迟一下,给grep时间parsinginput文件
  • 最后cat > file_name写入输出

也许你可以这样做:

 grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | cat > file_name