我有一个文件 temp.txt,我想用sort
bash 中的命令对其进行排序。
我希望排序结果替换原始文件。
例如,这不起作用(我得到一个空文件):
sortx temp.txt > temp.txt
这可以在一行中完成而无需复制到临时文件吗?
编辑:该-o
选项对于sort
. 我sort
以我的问题为例。我在使用其他命令时遇到了同样的问题:
uniq temp.txt > temp.txt.
有更好的通用解决方案吗?
我有一个文件 temp.txt,我想用sort
bash 中的命令对其进行排序。
我希望排序结果替换原始文件。
例如,这不起作用(我得到一个空文件):
sortx temp.txt > temp.txt
这可以在一行中完成而无需复制到临时文件吗?
编辑:该-o
选项对于sort
. 我sort
以我的问题为例。我在使用其他命令时遇到了同样的问题:
uniq temp.txt > temp.txt.
有更好的通用解决方案吗?
sort temp.txt -o temp.txt
Asort
需要先查看所有输入,然后才能开始输出。因此,该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
是不安全的,因为 sort 可能在读取完成F
之前开始写入cat
。
虽然 BSD 的文档sort
说:
如果 [the] 输出文件是输入文件之一,则 sort 在排序之前将其复制到一个临时文件并将输出写入 [the] 输出文件。
诸如此类的命令uniq
可以在完成读取输入之前开始写入输出。这些命令通常不支持就地编辑(它们更难支持此功能)。
您通常使用临时文件来解决此问题,或者如果您绝对希望避免使用中间文件,则可以使用缓冲区来存储完整的结果,然后再将其写出。例如,使用perl
:
uniq temp.txt | perl -e 'undef $/; $_ = <>; open(OUT,">temp.txt"); print OUT;'
uniq
在这里,perl 部分从in 变量中读取完整的输出$_
,然后用该数据覆盖原始文件。你可以用你选择的脚本语言做同样的事情,甚至可以用 Bash。但请注意,它需要足够的内存来存储整个文件,这在处理大文件时是不可取的。
这是一种更通用的方法,适用于 uniq、sort 等。
{ rm file && uniq > file; } < file
东武对海绵的评论本身就是一个答案。
引用moreutils主页:
到目前为止,moreutils 中最通用的工具可能是海绵(1),它可以让你做这样的事情:
% sed "s/root/toor/" /etc/passwd | grep -v joey | sponge /etc/passwd
然而,史蒂夫杰索普在这里评论sponge
同样的问题。如果之前管道中的任何命令失败,则将覆盖原始文件。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选项。这是手册页部分。
从手册页:
-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.
我喜欢这个sort file -o file
答案,但不想两次键入相同的文件名。
使用 BASH历史扩展:
$ sort file -o !#^
当您按下 时,获取当前行的第一个参数enter。
独特的就地排序:
$ sort -u -o file !#$
获取当前行中的最后一个参数。
这将受到高度内存限制,但您可以使用 awk 将中间数据存储在内存中,然后将其写回。
uniq temp.txt | awk '{line[i++] = $0}END{for(j=0;j<i;j++){print line[j]}}' > temp.txt
sponge
更常见的替代方法sed
:
sed -ni r<(command file) file
它适用于任何命令(sort
, uniq
, tac
, ...),并使用众所周知sed
的 's-i
选项(就地编辑文件)。
警告:首先尝试command file
,因为就地编辑文件本质上是不安全的。
首先,您要告诉sed
不要打印(原始)行(-n
选项),并且在sed
' r
command和bash
' Process Substitution的帮助下,生成的内容<(command file)
将是保存在原地的输出。
您可以将此解决方案包装成一个函数:
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
阅读非交互式编辑器,ex
.
使用参数--output=
或-o
刚刚在 FreeBSD 上试过:
sort temp.txt -otemp.txt
要添加该uniq
功能,有哪些缺点:
sort inputfile | uniq | sort -o inputfile
如果您坚持使用该sort
程序,则必须使用中间文件-我认为没有sort
在内存中排序的选项。stdin/stdout 的任何其他技巧都将失败,除非您可以保证 sort 的 stdin 的缓冲区大小足以容纳整个文件。
编辑:对我感到羞耻。sort temp.txt -o temp.txt
效果很好。
另一种解决方案:
uniq file 1<> file