uniq .bash_history > .bash_history
,我的历史记录文件最终完全为空。
我想我需要一种方法在写入文件之前先读取整个文件。
如何完成?
PS:我显然想过要使用临时文件,但我正在寻找更优雅的解决方案。
#1 楼
我建议使用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
评论
它就像猫,但具有吸吮能力:D
–MilliaLover
10年4月28日在0:11
#2 楼
echo "$(uniq .bash_history)" > .bash_history
应具有所需的结果。在打开
.bash_history
进行写入之前,将执行该子shell。如Phil P的答案所述,到原始命令中读取.bash_history
时,它已经被>
运算符截断了。评论
我今天用这个答案做echo“ $(fmt -p'#'-w 50 readme.txt)”> readme.txt。寻找了很长时间寻找一个优雅的解决方案。非常感谢,@ Hart Simha!
– shredalert
19年6月6日在12:05
如果回显中的命令引发错误,则将清除文件
–鲍里斯(Boris)
20年11月3日,19:06
#3 楼
问题是您的外壳在运行命令之前正在建立命令管道。这与“输入和输出”无关,因为文件的内容在uniq运行之前就已经消失了。它的内容类似于:shell打开
>
输出文件进行写入,将其截断shell设置为使用文件描述符1(用于stdout)用于输出结果
Shell执行uniq,也许类似于execlp(“ uniq”,“ uniq”,“ .bash_history”,NULL)
uniq运行,打开.bash_history,在此什么也没找到
有各种各样的解决方案,包括其他人提到的就地编辑和临时文件使用,但是关键是要了解问题,实际出了什么问题以及原因。
#4 楼
不使用sponge
的另一种方法是以下命令:{ rm .bash_history && uniq > .bash_history; } < .bash_history
这是出色的文章“就地”编辑中描述的作弊技巧之一backreference.org上的文件。
它基本上是打开文件进行读取,然后“删除”它。但是,它并没有真正被删除:有一个指向它的打开的文件描述符,只要保持打开状态,文件就仍然存在。然后,它将创建一个具有相同名称的新文件,并在其中写入唯一的行。
此解决方案的缺点:如果
uniq
由于某种原因失败,则您的历史记录将消失。#5 楼
使用moreutils提供的海绵uniq .bash_history | sponge .bash_history
#6 楼
作为一个有趣的花絮,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
描述:
临时文件
./sedPmPv9z
变成fd 4 ,并且foo
文件变成fd3。读取操作在fd 3上,写入在fd 4(临时文件)上。然后在重命名调用中用临时文件覆盖foo文件。#7 楼
此sed
脚本删除了相邻的重复项。使用-i
选项,它就地进行修改。来自sed
info
文件:sed -i 'h;:b;$b;N;/^\(.*\)\n$/ {g;bb};$b;P;D' .bash_history
评论
sed仍然使用temp文件,并添加了带有strace插图的答案(并不是真的很重要):-)
–凯尔·勃兰特(Kyle Brandt)
2010-4-25的1:15
@Kyle:的确如此,但是“视而不见,心不在“”。就个人而言,我会使用显式的临时文件,因为类似于sed欺骗,以避免输入临时文件,比起sed骗术,过程输入> tmp && mv tmp输入之类的东西更简单易读,并且在失败时也不会覆盖原始文件(我不会不知道sed -i是否正常失败-但我认为会)。此外,使用output-to-temp-file方法可以做很多事情,如果没有比这个sed脚本更复杂的事情,就无法就地完成。我知道您知道所有这一切,但这可能会使围观者受益。
–丹尼斯·威廉姆森
2010-4-25的2:54
#8 楼
另一个解决方案:uniq file 1<> líneas.txt
#9 楼
临时文件就差不多了,除非有问题的命令碰巧支持就地编辑(uniq
不支持-一些sed
可以(sed -i
))。#10 楼
您可以在Ex模式下使用Vim: ex -sc '%!uniq' -cx .bash_history
%
选择所有行!
运行命令x
保存并关闭#11 楼
您也可以使用tee,并使用uniq输出作为输入:uniq .bash_history | tee .bash_history
评论
不,您不能这样做askubuntu.com/a/752451
–史蒂芬·潘妮(Steven Penny)
16年4月23日在19:59
评论
这是因为文件是从右到左打开的。另请参见stackoverflow.com/questions/146435/…您必须将输出写入同一目录中的新文件,然后将其重命名为旧文件。如果其他方法中途中断,则可能会丢失数据。有些工具可能会让您看不到这一步。
或者,如果将HISTCONTROL设置为包含忽略的内容,bash不会在其历史记录中放置连续的重复对象;请参阅联机帮助页。
请考虑更改此答案。 serverfault.com/a/557566/130392