ファイルを編集するコマンド(引数)“ inplace”を実行する方法bashを使用していますか?

StackOverflow https://stackoverflow.com/questions/146435

  •  02-07-2019
  •  | 
  •  

質問

ファイルtemp.txtがあり、bashの sort コマンドでソートしたい。

ソートされた結果で元のファイルを置き換えたい。

これは、たとえば機能しません(空のファイルを取得します):

sortx temp.txt > temp.txt

これを一時ファイルにコピーせずに1行で実行できますか?


編集: -o オプションは、 sort にとって非常に便利です。例として質問で sort を使用しました。他のコマンドでも同じ問題が発生します:

uniq temp.txt > temp.txt.

より良い一般的な解決策はありますか?

役に立ちましたか?

解決

sort temp.txt -o temp.txt

他のヒント

A sort は、出力を開始する前にすべての入力を確認する必要があります。このため、 sort プログラムは、ファイルをその場で変更するオプションを簡単に提供できます。

sort temp.txt -o temp.txt

具体的には、 GNU sortのドキュメント のコメント:

  

通常、sortはoutput-fileを開く前にすべての入力を読み取るため、 sort -o F F cat F | sort -o F 。ただし、-merge -m )を指定した sort は、すべての入力を読み取る前に出力ファイルを開くことができるため、 cat F | sort -m -o F-G は、 cat が読み取りを完了する前に F の書き込みを開始する可能性があるため、安全ではありません。

BSDのドキュメントには、 sort には次のように書かれています:

  

[the] output-fileが入力ファイルの1つである場合、sortは、出力をソートして[the] output-fileに書き込む前に一時ファイルにコピーします。

uniq などのコマンドは、入力の読み取りを完了する前に出力の書き込みを開始できます。通常、これらのコマンドはインプレース編集をサポートしていません(そして、この機能をサポートするのはより困難です)。

通常、一時ファイルを使用してこの問題を回避します。または、中間ファイルを絶対に避けたい場合は、バッファを使用して完全な結果を保存してから書き出すことができます。たとえば、 perl

の場合
uniq temp.txt | perl -e 'undef $/; 

A sort は、出力を開始する前にすべての入力を確認する必要があります。このため、 sort プログラムは、ファイルをその場で変更するオプションを簡単に提供できます。

sort temp.txt -o temp.txt

具体的には、 GNU sortのドキュメント のコメント:

  

通常、sortはoutput-fileを開く前にすべての入力を読み取るため、 sort -o F F cat F | sort -o F 。ただし、-merge -m )を指定した sort は、すべての入力を読み取る前に出力ファイルを開くことができるため、 cat F | sort -m -o F-G は、 cat が読み取りを完了する前に F の書き込みを開始する可能性があるため、安全ではありません。

BSDのドキュメントには、 sort には次のように書かれています:

  

[the] output-fileが入力ファイルの1つである場合、sortは、出力をソートして[the] output-fileに書き込む前に一時ファイルにコピーします。

uniq などのコマンドは、入力の読み取りを完了する前に出力の書き込みを開始できます。通常、これらのコマンドはインプレース編集をサポートしていません(そして、この機能をサポートするのはより困難です)。

通常、一時ファイルを使用してこの問題を回避します。または、中間ファイルを絶対に避けたい場合は、バッファを使用して完全な結果を保存してから書き出すことができます。たとえば、 perl

の場合 <*>

ここで、perl部分は変数 $ _ uniq から完全な出力を読み取り、このデータで元のファイルを上書きします。お好みのスクリプト言語でも、おそらくBashでも同じことができます。ただし、ファイル全体を保存するのに十分なメモリが必要になることに注意してください。大きなファイルを扱う場合はお勧めできません。

= <>; 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 はなくなりました。

次の行に進みます:

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 !#$

現在の行の最後の引数を取得します。

多くの人が -o オプションについて言及しています。これがマニュアルページの部分です。

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++] = <*>}END{for(j=0;j<i;j++){print line[j]}}' > temp.txt

より一般的な sed による sponge の代替:

sed -ni r<(command file) file

任意のコマンド( sort uniq tac 、...)で動作し、よく知られている sedを使用します -i オプション(インプレースでファイルを編集)。

警告:ファイルをその場で編集することは本質的に安全ではないため、最初に command file を試してください。


説明

まず、(元の)行を印刷しないように sed に伝えています( -n オプション)、および sed r コマンドおよび bash プロセスの置換&lt;(コマンドファイル)は、インプレースに保存される出力になります。


物事をさらに簡単にする

このソリューションを関数にラップできます:

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

引数-output = または -o

を使用します

FreeBSDで試したところ:

sort temp.txt -otemp.txt

uniq 機能を追加するには、次の欠点があります:

sort inputfile | uniq | sort -o inputfile

非対話型エディター、 ex

sort プログラムの使用を主張する場合は、中間ファイルを使用する必要があります。 sort にはメモリ内でソートするオプションはないと思います。ソートのstdinのバッファーサイズがファイル全体に収まる大きさであることを保証できない限り、stdin / stdoutを使用したその他のトリックは失敗します。

編集:恥を知れ。 sort temp.txt -o temp.txt は優れた動作をします。

別の解決策:

uniq file 1<> file
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top