bashで次を実行しました。
uniq .bash_history > .bash_history
履歴ファイルは完全に空になりました。
書き込む前にファイル全体を読み取る方法が必要だと思います。どうやって?
PS:一時ファイルの使用を考えていましたが、よりエレガントなソリューションを探しています。
bash
HISTCONTROLを設定してignoreupsを含める場合、履歴に連続した重複を入れません。マンページを参照してください。
bashで次を実行しました。
uniq .bash_history > .bash_history
履歴ファイルは完全に空になりました。
書き込む前にファイル全体を読み取る方法が必要だと思います。どうやって?
PS:一時ファイルの使用を考えていましたが、よりエレガントなソリューションを探しています。
bash
HISTCONTROLを設定してignoreupsを含める場合、履歴に連続した重複を入れません。マンページを参照してください。
回答:
moreutilssponge
からの使用をお勧めします。マンページから:
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
望ましい結果が得られるはずです。サブシェルは、.bash_historyが書き込み用に開かれる前に実行されます。Phil Pの答えで説明したように、.bash_historyが元のコマンドで読み取られるまでに、 '>'演算子によって既に切り捨てられています。
$()
エスケープの問題があるため、バックティックの代わりにサブシェルを使用する必要がありました。
echo "$(fmt -p '# ' -w 50 readme.txt)" > readme.txt
今日はこの回答を使用しました。エレガントな解決策を長い間探し求めていました。@Hart Simha、ありがとう!
問題は、コマンドを実行する前にシェルがコマンドパイプラインを設定していることです。「入力と出力」の問題ではなく、uniqが実行される前にファイルのコンテンツがすでに削除されているということです。次のようになります:
>
出力ファイルを書き込み用に開き、切り捨てますインプレース編集や一時ファイルの使用など、さまざまなソリューションがありますが、重要なのは、問題、実際に何が問題になっているのか、そしてその理由を理解することです。
を使用せずにこれを行う別のトリックsponge
は、次のコマンドです。
{ rm .bash_history && uniq > .bash_history; } < .bash_history
これは、backreference.orgの優れた記事「ファイルのインプレース編集」で説明されているチートの1つです。
基本的に読み取り用にファイルを開き、それを「削除」します。ただし、実際には削除されていません。それを指すオープンファイル記述子があり、それが開いたままである限り、ファイルはまだ存在しています。次に、同じ名前の新しいファイルを作成し、一意の行を書き込みます。
このソリューションの欠点:uniq
何らかの理由で失敗した場合、履歴は失われます。
moreutilsのスポンジを使用する
uniq .bash_history | sponge .bash_history
このsed
スクリプトは、隣接する重複を削除します。では-i
オプション、それはその場で修正を行います。それはsed
info
ファイルからです:
sed -i 'h;:b;$b;N;/^\(.*\)\n\1$/ {g;bb};$b;P;D' .bash_history
strace
イラスト付きの回答を追加しました(実際には重要ではありません):
process input > tmp && mv tmp input
はsed
、一時ファイルを避けるためにトリックを使用するよりもはるかにシンプルで読みやすいので、明示的な一時ファイルを使用します。失敗した場合、元のファイルは上書きされません(sed -i
正常に失敗したかどうかはわかりません-私はしかしそれだと思います)。それに、temp-to-temp-fileに出力する方法でできることはたくさんありますが、このsed
スクリプトよりも複雑なものがなければ、インプレースで行うことはできません。あなたはこれをすべて知っていることを知っていますが、それは見物人の利益になるかもしれません。
興味深いヒントとして、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
ファイルはfd 3になります。読み取り操作はfd 3で行われ、書き込みはfd 4(一時ファイル)で行われます。fooファイルは、名前変更呼び出しで一時ファイルで上書きされます。
別の解決策:
uniq file 1<> líneas.txt
入力としてuniq出力を使用して、teeも使用できます。
uniq .bash_history | tee .bash_history