
[code]

    $ cat hoge.txt > hoge.txt
    
[/code]

これを実行すると、「`hoge.txt`の中身がそのまま`hoge.txt`に書き出されて結果的に中身は同じになる」と思っていたのですが、実行してみるとファイルの中身が空になり、容量も0バイトになってしまいます。

他のコマンドでも同様に読み込みファイルにたいして`>`をつかって上書きしようとすると中身が消えてしまいます。

上書きしたい場合はどうしたらよいのでしょうか。


CC BY-SA 3.0
2017-05-25T13:21:14.990
35012
2018-12-06T03:46:44.823
9149
question
linux unix
コマンドラインで読み込んだファイルに上書きするには


リダイレクトはコマンドが実行される前に shell が処理してしまってますから、コマンドが実行された時には既にファイルは空になっています。

出力を一旦別ファイルに格納するしかないのでは?

[code]

    cat hoge.txt > tmp
    mv tmp hoge.txt
    
[/code]


CC BY-SA 3.0
2017-05-25T13:58:32.997
35013
2017-05-25T13:58:32.997
5288
35012
answer


`GNU cat` だとその構文はエラーになります。

[code]

    $ cat hoge.txt > hoge.txt
    cat: hoge.txt: input file is output file
    
[/code]

次のようなやり方はどうでしょう。

[code]

    $ cat hoge.txt | bash -c 'cat - > hoge.txt'
    
[/code]


CC BY-SA 3.0
2017-05-25T14:24:38.767
35014
2017-05-25T14:24:38.767
5008
35012
answer


シェルがコマンドラインを解釈した後、`hoge.txt` をオープンして 0 バイトにしてから `cat`
を起動するので当然の結果です。実行したいコマンドラインの前に `hoge.txt`
を一時ファイルにコピーして利用するか、実行結果を一時ファイルに出力したあと上書きする必要があります。

moreutils の `sponge`(1) が利用できる環境ならば、一時ファイルは不要で次のように実行できます。

[code]

    cat hoge.txt |sponge hoge.txt
    
[/code]

なお、ほかの回答にある元ファイルを一旦削除する方法は、元ファイルのファイル所有者とアクセス権が失なわれる可能性があるので注意が必要です。


CC BY-SA 4.0
2017-05-25T15:46:30.157
35017
2018-12-06T03:46:44.823
2018-12-06T03:46:44.823
3061
3061
35012
answer


黒魔術的ではありますが、以下のようにするとUNIXとシェルの機能のみで中間ファイルを利用することなく実現できます。

[code]

    (rm -f hoge.txt && cat > hoge.txt) < hoge.txt
    
[/code]

cat だと分かりにくいので、`sort` を使った例:

[code]

    % cat hoge.txt
    3
    1
    2
    % (rm -f hoge.txt && sort > hoge.txt) < hoge.txt
    % cat hoge.txt
    1
    2
    3
    
[/code]

オープンしたファイルを削除しても、クローズされるまではファイル本体が残っている (読み書き可能) であることを利用 (悪用?) しています。

参考: <https://twitter.com/kuwashima/status/854716064109699072>


CC BY-SA 3.0
2017-05-26T01:18:19.583
35022
2017-05-26T01:18:19.583
76
35012
answer