如何执行任何命令编辑其文件(参数)“到位”使用bash?

StackOverflow https://stackoverflow.com/questions/146435

  •  02-07-2019
  •  | 
  •  

我有一个文件temp.txt,我想在bash中使用 sort 命令进行排序。

我希望排序结果替换原始文件。

这不起作用(我得到一个空文件):

sortx temp.txt > temp.txt

这可以在一行中完成而无需复制到临时文件吗?


编辑: -o 选项对 sort 来说非常酷。我在我的问题中使用 sort 作为示例。我遇到了与其他命令相同的问题:

uniq temp.txt > temp.txt.

有更好的通用解决方案吗?

有帮助吗?

解决方案

sort temp.txt -o temp.txt

其他提示

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

sort temp.txt -o temp.txt

具体来说, GNU sort的文档 说:

  

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

虽然BSD sort 的文档说:

  

如果[the]输出文件是输入文件之一,则在排序并将输出写入[output]文件之前,将其复制到临时文件中。

uniq 之类的命令可以在读完输入之前开始写输出。这些命令通常不支持就地编辑(并且它们更难以支持此功能)。

您通常使用临时文件解决此问题,或者如果您绝对想要避免使用中间文件,则可以在写出之前使用缓冲区存储完整的结果。例如,使用 perl

uniq temp.txt | perl -e 'undef $/; 

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

sort temp.txt -o temp.txt

具体来说, GNU sort的文档 说:

  

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

虽然BSD sort 的文档说:

  

如果[the]输出文件是输入文件之一,则在排序并将输出写入[output]文件之前,将其复制到临时文件中。

uniq 之类的命令可以在读完输入之前开始写输出。这些命令通常不支持就地编辑(并且它们更难以支持此功能)。

您通常使用临时文件解决此问题,或者如果您绝对想要避免使用中间文件,则可以在写出之前使用缓冲区存储完整的结果。例如,使用 perl

<*>

这里,perl部分从变量 $ _ 中的 uniq 读取完整输出,然后用这些数据覆盖原始文件。您可以使用您选择的脚本语言执行相同的操作,甚至可以使用Bash。但请注意,它需要足够的内存来存储整个文件,这在处理大文件时是不可取的。

= <>; open(OUT,">temp.txt"); print OUT;'

这里,perl部分从变量 $ _ 中的 uniq 读取完整输出,然后用这些数据覆盖原始文件。您可以使用您选择的脚本语言执行相同的操作,甚至可以使用Bash。但请注意,它需要足够的内存来存储整个文件,这在处理大文件时是不可取的。

这是一种更通用的方法,适用于uniq,sort和whatnot。

{ rm file && uniq > file; } < file

东武对海绵的评论保证本身就是一个答案。

引用 moreutils 主页:

  

到目前为止,moreutils中最常用的工具可能是海绵(1),它允许你做这样的事情:

% sed "s/root/toor/" /etc/passwd | grep -v joey | sponge /etc/passwd

然而, sponge 会遇到同样的问题 Steve Jessop在这里发表评论。如果有的话在 sponge 失败之前管道中的命令,然后原始文件将被写入。

$ mistyped_command my-important-file | sponge my-important-file
mistyped-command: command not found

呃 - 哦, my-important-file 消失了。

你走了,一行:

sort temp.txt > temp.txt.sort && mv temp.txt.sort temp.txt

从技术上讲,没有复制到临时文件,'mv'命令应该是即时的。

我喜欢排序文件-o file 的答案,但不想两次输入相同的文件名。

使用BASH 历史记录扩展

$ sort file -o !#^
输入时,

抓取当前行的第一个arg。

一种独特的原位排序:

$ sort -u -o file !#$

抓住当前行中的最后一个arg。

许多人都提到了 -o 选项。这是手册页部分。

从手册页:

   -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.

这会受到高度内存限制,但您可以使用awk将中间数据存储在内存中,然后将其写回。

uniq temp.txt | awk '{line[i++] = <*>}END{for(j=0;j<i;j++){print line[j]}}' > temp.txt

使用更常见的 sed 替代 sponge

sed -ni r<(command file) file

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

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


解释

首先,你告诉 sed 不要打印(原始)行( -n 选项),并借助 sed r 命令 bash 进程替换&lt;(命令文件)生成的内容将输出保存到位


让事情变得更加轻松

您可以将此解决方案包装到一个函数中:

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"
}

实施例

$ 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

使用参数 - output = -o

刚试过FreeBSD:

sort temp.txt -otemp.txt

要添加 uniq 功能,有什么缺点:

sort inputfile | uniq | sort -o inputfile

阅读非交互式编辑器, ex

如果你坚持使用 sort 程序,你必须使用一个中间文件 - 我不认为 sort 有一个在内存中排序的选项。除非你能保证sort的stdin的缓冲区大小足以适合整个文件,否则stdin / stdout的任何其他技巧都将失败。

编辑:对我感到羞耻。 sort temp.txt -o temp.txt 效果很好。

另一种解决方案:

uniq file 1<> file
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top