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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 17:42:20  来源:igfitidea点击:

How do I execute any command editing its file (argument) "in place" using bash?

bashcommand-linesorting

提问by jm.

I have a file temp.txt, that I want to sort with the sortcommand in bash.

我有一个文件 temp.txt,我想用sortbash 中的命令对其进行排序。

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 -ooption is very cool for sort. I used sortin 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 sortneeds to see all input before it can start to output. For this reason, the sortprogram can easily offer an option to modify a file in-place:

Asort在开始输出之前需要查看所有输入。出于这个原因,该sort程序可以轻松提供一个选项来就地修改文件:

sort temp.txt -o temp.txt

Specifically, the documentation of GNU sortsays:

具体来说,GNUsort文档说:

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 Fand cat F | sort -o F. However, sortwith --merge(-m) can open the output file before reading all input, so a command like cat F | sort -m -o F - Gis not safe as sort might start writing Fbefore catis done reading it.

通常, sort 在打开输出文件之前读取所有输入,因此您可以使用sort -o F F和 之类的命令安全地对文件进行排序cat F | sort -o F。但是,sort使用--merge( -m) 可以在读取所有输入之前打开输出文件,因此像cat F | sort -m -o F - Gsort这样的命令可能Fcat读取完成之前开始写入是不安全的。

While the documentation of BSD sortsays:

虽然 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 uniqcan 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 uniqin 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 部分从uniqin 变量中读取完整的输出$_,然后用这些数据覆盖原始文件。您可以使用您选择的脚本语言执行相同的操作,甚至可以使用 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, spongesuffers from the same problem Steve Jessop comments on here.If any of the commands in the pipeline before spongefail, 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-fileis 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 fileanswer 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 spongewith 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 -ioption(edit files in-place).

它适用于任何命令 ( sort, uniq, tac, ...) 并使用众所周知的sed's-i选项(就地编辑文件)。

Warning:Try command filefirst because editing files in-place is not safe by nature.

警告:command file首先尝试,因为就地编辑文件本质上并不安全。



Explanation

解释

Firstly, you're telling sednot to print the (original) lines (-noption), and with the help of the sed's rcommandand bash's Process Substitution, the generated content by <(command file)will be the output saved in place.

首先,您告诉sed不要打印(原始)行(-n选项),并且在sed's rcommandbash'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 uniqcapability, what are the downsides to:

要添加该uniq功能,有哪些缺点:

##代码##