Bashのsort
コマンドでソートしたいtemp.txtファイルがあります。
ソートされた結果で元のファイルを置き換えたいです。
これは例えば機能しません(空のファイルを取得します):
sortx temp.txt > temp.txt
これは、一時ファイルへのコピーに頼らずに1行で実行できますか?
編集:-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はoutput-fileを開く前にすべての入力を読み取るため、
sort -o F F
やcat F | sort -o F
などのコマンドを使用して、ファイルを所定の場所に安全にソートできます。ただし、sort
with--merge
(-m
)はすべての入力を読み取る前に出力ファイルを開くことができるため、cat F | sort -m -o F - G
などのコマンドは安全ではありません。ソートはF
cat
が読み込まれる前。
BSDのドキュメントsort
は次のように述べています:
[the] output-fileが入力ファイルの1つである場合、sortは、出力を[the] output-fileにソートして書き込む前に、それを一時ファイルにコピーします。
uniq
などのコマンドは、入力の読み取りを完了する前に出力の書き込みを開始できます。これらのコマンドは通常、インプレース編集をサポートしていません(この機能をサポートすることは困難です)。
通常、一時ファイルを使用してこの問題を回避します。中間ファイルを絶対に避けたい場合は、バッファを使用して完全な結果を保存してから書き出すことができます。たとえば、Perl
の場合:
uniq temp.txt | Perl -e 'undef $/; $_ = <>; open(OUT,">temp.txt"); print OUT;'
ここでは、Perl部分は、変数$_
のuniq
から完全な出力を読み取り、このデータで元のファイルを上書きします。お好みのスクリプト言語でも、おそらくBashでも同じことができます。ただし、ファイル全体を保存するのに十分なメモリが必要になることに注意してください。大きなファイルを操作する場合はお勧めできません。
以下に、より一般的なアプローチを示します。uniq、sort、その他の方法で動作します。
{ rm file && uniq > file; } < file
スポンジに関する東武のコメント それ自体が答えであることを保証します。
moreutils ホームページから引用するには:
おそらく、これまでのmoreutilsの最も汎用的なツールはsponge(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
なくなっている。
ここで、1行:
sort temp.txt > temp.txt.sort && mv temp.txt.sort temp.txt
技術的には、一時ファイルへのコピーはなく、「mv」コマンドは即座に実行されるはずです。
私は好き sort file -o file
答えますが、同じファイル名を2回入力したくないです。
BASHの使用 履歴展開 :
$ sort file -o !#^
を押すと、現在の行の最初の引数を取得します enter。
その場でのユニークなソート:
$ sort -u -o file !#$
現在の行の最後の引数を取得します。
sponge
の代わりに、より一般的なsed
を使用:
_sed -ni r<(command file) file
_
任意のコマンド(sort
、uniq
、tac
、...)で動作し、よく知られているsed
の- _-i
_ option (インプレースでファイルを編集)。
警告:最初に_command file
_を試してください。インプレースでファイルを編集することは本質的に安全ではありません。
まず、(元の)行を印刷しないようにsed
に指示しています( _-n
_オプション )、およびsed
の助けを借りて- r
command and bash
's Process Substitution 、<(command file)
によって生成されたコンテンツは保存された出力になりますin place。
このソリューションを関数にラップできます。
_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
_
多くの人が-oオプションに言及しています。これがmanページの部分です。
Manページから:
-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++] = $0}END{for(j=0;j<i;j++){print line[j]}}' > temp.txt
非対話型エディタ ex
を参照してください。
引数--output=
または-o
を使用します
FreeBSDで試しました:
sort temp.txt -otemp.txt
uniq
機能を追加するには、次の欠点があります。
sort inputfile | uniq | sort -o inputfile
sort
プログラムの使用を主張する場合は、中間ファイルを使用する必要があります-sort
にはメモリ内でソートするオプションはないと思います。ソートのstdinのバッファーサイズがファイル全体に適合するのに十分であることを保証できない限り、stdin/stdoutを使用したその他のトリックは失敗します。
編集:恥を知れ。 sort temp.txt -o temp.txt
優れた動作。
別の解決策:
uniq file 1<> file