我刚刚在bash中运行以下内容:
uniq .bash_history > .bash_history
我的历史档案完全空了。
我想我需要一种方法来在写入之前阅读整个文件。 这是怎么做的?
PS:我明显想到使用一个临时文件,但我正在寻找一个更优雅的解决scheme。
我build议使用moreutils的 sponge
。 从手册:
DESCRIPTION sponge reads standard input and writes it out to the specified file. Unlike a shell redirect, sponge soaks up all its input before opening the output file. This allows for constructing pipelines that read from and write to the same file.
要将此应用于您的问题,请尝试:
uniq .bash_history | sponge .bash_history
我只是想贡献一个简单的答案,而不使用海绵(因为它通常不包含在轻量级环境中)。
echo "$(uniq .bash_history)" > .bash_history
应该有理想的结果。 子shell在执行之前.bash_history打开写入。 正如Phil P的回答中所解释的那样,在原始命令中读取.bash_history时,它已经被'>'运算符截断。
问题是你的shell在运行这些命令之前正在设置命令pipe道。 这不是“input和输出”的问题,而是在uniq运行之前文件的内容已经消失了。 它是这样的:
>
输出文件进行写入,将其截断 有很多解决scheme,包括其他人提到的就地编辑和临时文件使用,但关键是要了解问题,实际发生了什么问题,为什么。
使用moreutils的海绵
uniq .bash_history | sponge .bash_history
另一个不使用sponge
是使用以下命令:
{ rm .bash_history && uniq > .bash_history; } < .bash_history
这是在backreference.org 文件的“就地”编辑文件中描述的作弊手段之一。
它基本上打开文件阅读,然后“删除”它。 但是,它并没有真正被删除:有一个打开的文件描述符指向它,只要保持打开状态,文件仍然存在。 然后它创build一个具有相同名称的新文件,并将唯一的行写入它。
这个解决scheme的缺点:如果uniq
由于某种原因失败,你的历史将会消失。
这个sed
脚本删除相邻的重复项。 使用-i
选项,它会就地进行修改。 它来自sed
info
文件:
sed -i 'h;:b;$b;N;/^\(.*\)\n\1$/ {g;bb};$b;P;D' .bash_history
作为一个有趣的消息,sed也使用临时文件(这只是为你做的):
$ strace sed -i 's/foo/bar/g' foo open("foo", O_RDONLY|O_LARGEFILE) = 3 ... open("./sedPmPv9z", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600) = 4 ... read(3, "foo\n"..., 4096) = 4 write(4, "bar\n"..., 4) = 4 read(3, ""..., 4096) = 0 close(3) = 0 close(4) = 0 rename("./sedPmPv9z", "foo") = 0 close(1) = 0 close(2) = 0
描述:
tempfile ./sedPmPv9z
变成fd 4, foo
文件变成fd 3.读取操作在fd 3上,在fd 4(临时文件)上写入。 在重命名调用中,foo文件将被临时文件覆盖。
一个临时文件是非常多的,除非有问题的命令恰好支持就地编辑( uniq
不 – 有些sed
s do( sed -i
))。
您可以在Ex模式下使用Vim:
ex -sc '%!uniq' -cx .bash_history
%
select所有行
!
运行命令
保存并closures
另一个scheme
uniq file 1<> líneas.txt
您也可以使用tee,使用uniq输出作为input:
uniq .bash_history | tee .bash_history