如何执行任何命令编辑其文件(参数)“到位”使用bash?
-
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