基本上我想从文件中取输入文本,从该文件中删除一行,然后将输出发送回同一文件.沿着这些方向的东西,如果这使它更清楚.
grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > file_name
Run Code Online (Sandbox Code Playgroud)
但是,当我这样做时,我最终得到一个空白文件.有什么想法吗?
Lyn*_*nch 80
用海绵做这种任务.它是moreutils的一部分.
试试这个命令:
grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | sponge file_name
Run Code Online (Sandbox Code Playgroud)
c00*_*ter 76
你不能这样做,因为bash首先处理重定向,然后执行命令.所以当grep查看file_name时,它已经是空的.您可以使用临时文件.
#!/bin/sh
tmpfile=$(mktemp)
grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > ${tmpfile}
cat ${tmpfile} > file_name
rm -f ${tmpfile}
Run Code Online (Sandbox Code Playgroud)
像这样,考虑使用mktemp
创建tmp文件,但请注意它不是POSIX.
Man*_*y D 17
请改用sed:
sed -i '/seg[0-9]\{1,\}\.[0-9]\{1\}/d' file_name
Run Code Online (Sandbox Code Playgroud)
小智 9
试试这个简单的
grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | tee file_name
Run Code Online (Sandbox Code Playgroud)
这次你的文件不会是空白的:)你的输出也会打印到你的终端.
您不能对同一文件使用重定向运算符(>
或>>
),因为它具有更高的优先级,并且会在调用该命令之前创建/截断该文件。为了避免这种情况,你应该使用合适的工具,例如tee
,sponge
,sed -i
或任何其他工具,它可以将结果写到文件(例如sort file -o file
)。
基本上将输入重定向到相同的原始文件是没有意义的,您应该为此使用适当的就地编辑器,例如Ex编辑器(Vim的一部分):
ex '+g/seg[0-9]\{1,\}\.[0-9]\{1\}/d' -scwq file_name
Run Code Online (Sandbox Code Playgroud)
哪里:
'+cmd'
/ -c
-运行任何Ex / Vim命令g/pattern/d
-使用全局(help :g
)删除与模式匹配的行-s
-静音模式(man ex
)-c wq
-执行:write
和:quit
命令您可以使用sed
来实现相同的(在其他的答案已经显示),但就地(-i
)是非标准的FreeBSD扩展(可以在Unix / Linux之间的工作方式不同),基本上它是一个小号 tream 版 itor,而不是一个文件编辑器。请参阅:防爆模式有实际用途吗?
这是很有可能的,您只需确保在写入输出时,将其写入不同的文件即可。这可以通过在打开文件描述符之后但在写入文件之前删除该文件来完成:
exec 3<file ; rm file; COMMAND <&3 >file ; exec 3>&-
Run Code Online (Sandbox Code Playgroud)
或者逐行,以便更好地理解它:
exec 3<file # open a file descriptor reading 'file'
rm file # remove file (but fd3 will still point to the removed file)
COMMAND <&3 >file # run command, with the removed file as input
exec 3>&- # close the file descriptor
Run Code Online (Sandbox Code Playgroud)
这仍然是一件有风险的事情,因为如果 COMMAND 无法正常运行,您将丢失文件内容。如果 COMMAND 返回非零退出代码,可以通过恢复文件来缓解这种情况:
exec 3<file ; rm file; COMMAND <&3 >file || cat <&3 >file ; exec 3>&-
Run Code Online (Sandbox Code Playgroud)
我们还可以定义一个 shell 函数以使其更易于使用:
# Usage: replace FILE COMMAND
replace() { exec 3<$1 ; rm $1; ${@:2} <&3 >$1 || cat <&3 >$1 ; exec 3>&- }
Run Code Online (Sandbox Code Playgroud)
例子 :
$ echo aaa > test
$ replace test tr a b
$ cat test
bbb
Run Code Online (Sandbox Code Playgroud)
另请注意,这将保留原始文件的完整副本(直到第三个文件描述符关闭)。如果您使用的是 Linux,并且您正在处理的文件太大,无法在磁盘上放置两次,您可以查看此脚本,该脚本将通过管道将文件逐块传输到指定的命令,同时取消分配已处理的文件块。与往常一样,请阅读使用页面中的警告。
一种衬板替代方案-将文件的内容设置为变量:
VAR=`cat file_name`; echo "$VAR"|grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' > file_name
Run Code Online (Sandbox Code Playgroud)
由于这个问题是搜索引擎中的最高结果,这里有一个基于https://serverfault.com/a/547331的单行,它使用子外壳而不是sponge
(通常不是像 OS X 这样的香草安装的一部分) :
echo "$(grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name)" > file_name
Run Code Online (Sandbox Code Playgroud)
一般情况是:
echo "$(cat file_name)" > file_name
Run Code Online (Sandbox Code Playgroud)
编辑,上述解决方案有一些警告:
printf '%s' <string>
应该使用而不是echo <string>
这样,包含的文件-n
不会导致不良行为。x
在输出中附加一个后缀字符,并通过临时变量的参数扩展(如${v%x}
.$v
破坏$v
当前 shell 环境中任何现有变量的值,因此我们应该将整个表达式嵌套在括号中以保留先前的值。null
从输出中删除不可打印的字符。我通过dd if=/dev/zero bs=1 count=1 >> file_name
使用cat file_name | xxd -p
. 但是echo $(cat file_name) | xxd -p
被剥光了。因此,正如Lynch 指出的那样,此答案不应用于二进制文件或任何使用不可打印字符的内容。一般的解决方案(虽然稍微慢一点,更多的内存密集型,仍然剥离不可打印的字符)是:
(v=$(cat file_name; printf x); printf '%s' ${v%x} > file_name)
Run Code Online (Sandbox Code Playgroud)
从https://askubuntu.com/a/752451测试:
printf "hello\nworld\n" > file_uniquely_named.txt && for ((i=0; i<1000; i++)); do (v=$(cat file_uniquely_named.txt; printf x); printf '%s' ${v%x} > file_uniquely_named.txt); done; cat file_uniquely_named.txt; rm file_uniquely_named.txt
Run Code Online (Sandbox Code Playgroud)
应该打印:
hello
world
Run Code Online (Sandbox Code Playgroud)
而cat file_uniquely_named.txt > file_uniquely_named.txt
在当前 shell 中调用:
printf "hello\nworld\n" > file_uniquely_named.txt && for ((i=0; i<1000; i++)); do cat file_uniquely_named.txt > file_uniquely_named.txt; done; cat file_uniquely_named.txt; rm file_uniquely_named.txt
Run Code Online (Sandbox Code Playgroud)
打印一个空字符串。
我还没有在大文件(可能超过 2 或 4 GB)上测试过这个。
我从Hart Simha和kos借用了这个答案。