bash 如何使用bash“就地”执行编辑其文件(参数)的任何命令?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/146435/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I execute any command editing its file (argument) "in place" using bash?
提问by jm.
I have a file temp.txt, that I want to sort with the sort
command in bash.
我有一个文件 temp.txt,我想用sort
bash 中的命令对其进行排序。
I want the sorted results to replace the original file.
我希望排序结果替换原始文件。
This doesn't work for example (I get an empty file):
例如,这不起作用(我得到一个空文件):
sortx temp.txt > temp.txt
Can this be done in one line without resorting to copying to temporary files?
这可以在一行中完成而无需复制到临时文件吗?
EDIT: The -o
option is very cool for sort
. I used sort
in my question as an example. I run into the same problem with other commands:
编辑:该-o
选项对于sort
. 我sort
以我的问题为例。我在使用其他命令时遇到了同样的问题:
uniq temp.txt > temp.txt.
Is there a better general solution?
有没有更好的通用解决方案?
回答by daniels
sort temp.txt -o temp.txt
回答by Bruno De Fraine
A sort
needs to see all input before it can start to output. For this reason, the sort
program can easily offer an option to modify a file in-place:
Asort
在开始输出之前需要查看所有输入。出于这个原因,该sort
程序可以轻松提供一个选项来就地修改文件:
sort temp.txt -o temp.txt
Specifically, the documentation of GNU sort
says:
Normally, sort reads all input before opening output-file, so you can safely sort a file in place by using commands like
sort -o F F
andcat F | sort -o F
. However,sort
with--merge
(-m
) can open the output file before reading all input, so a command likecat F | sort -m -o F - G
is not safe as sort might start writingF
beforecat
is done reading it.
通常, sort 在打开输出文件之前读取所有输入,因此您可以使用
sort -o F F
和 之类的命令安全地对文件进行排序cat F | sort -o F
。但是,sort
使用--merge
(-m
) 可以在读取所有输入之前打开输出文件,因此像cat F | sort -m -o F - G
sort这样的命令可能F
在cat
读取完成之前开始写入是不安全的。
While the documentation of BSD sort
says:
虽然 BSD 的文档sort
说:
If [the] output-file is one of the input files, sort copies it to a temporary file before sorting and writing the output to [the] output-file.
如果 [the] output-file 是输入文件之一, sort 将它复制到一个临时文件,然后排序并将输出写入 [the] output-file。
Commands such as uniq
can start writing output before they finish reading the input. These commands typically do not support in-place editing (and it would be harder for them to support this feature).
命令uniq
可以在完成读取输入之前开始写入输出。这些命令通常不支持就地编辑(并且它们更难支持此功能)。
You typically work around this with a temporary file, or if you absolutely want to avoid having an intermediate file, you could use a buffer to store the complete result before writing it out. For example, with perl
:
您通常使用临时文件来解决这个问题,或者如果您绝对想避免使用中间文件,您可以在写出之前使用缓冲区来存储完整的结果。例如,使用perl
:
uniq temp.txt | perl -e 'undef $/; $_ = <>; open(OUT,">temp.txt"); print OUT;'
Here, the perl part reads the complete output from uniq
in variable $_
and then overwrites the original file with this data. You could do the same in the scripting language of your choice, perhaps even in Bash. But note that it will need enough memory to store the entire file, this is not advisable when working with large files.
在这里,perl 部分从uniq
in 变量中读取完整的输出$_
,然后用这些数据覆盖原始文件。您可以使用您选择的脚本语言执行相同的操作,甚至可以使用 Bash。但请注意,它需要足够的内存来存储整个文件,这在处理大文件时是不可取的。
回答by wor
Here's a more general approach, works with uniq, sort and whatnot.
这是一种更通用的方法,适用于 uniq、sort 等。
{ rm file && uniq > file; } < file
回答by Sean
Tobu's comment on spongewarrants being an answer in its own right.
东武对海绵的评论本身就是一个答案。
To quote from the moreutilshomepage:
引用moreutils主页:
Probably the most general purpose tool in moreutils so far is sponge(1), which lets you do things like this:
% sed "s/root/toor/" /etc/passwd | grep -v joey | sponge /etc/passwd
到目前为止,moreutils 中最通用的工具可能是海绵 (1),它可以让你做这样的事情:
% sed "s/root/toor/" /etc/passwd | grep -v joey | sponge /etc/passwd
However, sponge
suffers from the same problem Steve Jessop comments on here.If any of the commands in the pipeline before sponge
fail, then the original file will be written over.
然而,Steve Jessop 在这里评论sponge
了同样的问题。如果之前管道中的任何命令sponge
失败,则原始文件将被覆盖。
$ mistyped_command my-important-file | sponge my-important-file
mistyped-command: command not found
Uh-oh, my-important-file
is gone.
呵呵,my-important-file
不见了。
回答by davr
Here you go, one line:
给你,一行:
sort temp.txt > temp.txt.sort && mv temp.txt.sort temp.txt
Technically there's no copying to a temporary file, and the 'mv' command should be instant.
从技术上讲,不会复制到临时文件,“mv”命令应该是即时的。
回答by johnnyB
I like the sort file -o file
answer but don't want to type the same file name twice.
我喜欢这个sort file -o file
答案,但不想输入相同的文件名两次。
Using BASH history expansion:
使用 BASH历史扩展:
$ sort file -o !#^
grabs the current line's first arg when you press enter.
当您按下 时,抓取当前行的第一个 arg enter。
A unique sort in-place:
独特的就地排序:
$ sort -u -o file !#$
grabs the last arg in the current line.
获取当前行中的最后一个 arg。
回答by whoan
An alternative to sponge
with the more common sed
:
sponge
更常见的替代方法sed
:
sed -ni r<(command file) file
It works for any command (sort
, uniq
, tac
, ...) and uses the very well known sed
's -i
option(edit files in-place).
它适用于任何命令 ( sort
, uniq
, tac
, ...) 并使用众所周知的sed
's-i
选项(就地编辑文件)。
Warning:Try command file
first because editing files in-place is not safe by nature.
警告:command file
首先尝试,因为就地编辑文件本质上并不安全。
Explanation
解释
Firstly, you're telling sed
not to print the (original) lines (-n
option), and with the help of the sed
's r
commandand bash
's Process Substitution, the generated content by <(command file)
will be the output saved in place.
首先,您告诉sed
不要打印(原始)行(-n
选项),并且在sed
's r
command和bash
's Process Substitution的帮助下,生成的内容<(command file)
将是原地保存的输出。
Making things even easier
让事情变得更容易
You can wrap this solution into a function:
您可以将此解决方案包装到一个函数中:
ip_cmd() { # in place command
CMD=${1:?You must specify a command}
FILE=${2:?You must specify a file}
sed -ni r<("$CMD" "$FILE") "$FILE"
}
Example
例子
$ cat file
d
b
c
b
a
$ ip_cmd sort file
$ cat file
a
b
b
c
d
$ ip_cmd uniq file
$ cat file
a
b
c
d
$ ip_cmd tac file
$ cat file
d
c
b
a
$ ip_cmd
bash: 1: You must specify a command
$ ip_cmd uniq
bash: 2: You must specify a file
回答by epatel
Many have mentioned the -ooption. Here is the man page part.
许多人提到了-o选项。这是手册页部分。
From the man page:
从手册页:
-o output-file
Write output to output-file instead of to the standard output.
If output-file is one of the input files, sort copies it to a
temporary file before sorting and writing the output to output-
file.
回答by JayG
This would be highly memory constrained, but you could use awk to store the intermediate data in memory, and then write it back out.
这将受到高度内存限制,但您可以使用 awk 将中间数据存储在内存中,然后将其写回。
uniq temp.txt | awk '{line[i++] = sort inputfile | uniq | sort -o inputfile
}END{for(j=0;j<i;j++){print line[j]}}' > temp.txt
回答by jasper
To add the uniq
capability, what are the downsides to:
要添加该uniq
功能,有哪些缺点: