How can I use a file in a command and redirect output to the same file without truncating it?

前端 未结 14 2793
终归单人心
终归单人心 2020-11-21 22:11

Basically I want to take as input text from a file, remove a line from that file, and send the output back to the same file. Something along these lines if that makes it any

14条回答
  •  执笔经年
    2020-11-21 22:52

    This is very much possible, you just have to make sure that by the time you write the output, you're writing it to a different file. This can be done by removing the file after opening a file descriptor to it, but before writing to it:

    exec 3file ;  exec 3>&-
    

    Or line by line, to understand it better :

    exec 3file # run command, with the removed file as input
    exec 3>&-         # close the file descriptor
    

    It's still a risky thing to do, because if COMMAND fails to run properly, you'll lose the file contents. That can be mitigated by restoring the file if COMMAND returns a non-zero exit code :

    exec 3file || cat <&3 >file ; exec 3>&-
    

    We can also define a shell function to make it easier to use :

    # Usage: replace FILE COMMAND
    replace() { exec 3<$1 ; rm $1; ${@:2} <&3 >$1 || cat <&3 >$1 ; exec 3>&- }
    

    Example :

    $ echo aaa > test
    $ replace test tr a b
    $ cat test
    bbb
    

    Also, note that this will keep a full copy of the original file (until the third file descriptor is closed). If you're using Linux, and the file you're processing on is too big to fit twice on the disk, you can check out this script that will pipe the file to the specified command block-by-block while unallocating the already processed blocks. As always, read the warnings in the usage page.

提交回复
热议问题