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/截断文件。 为了避免这种情况,你应该使用适当的工具,例如tee
, sponge
, sed -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