sed in-place flag that works both on Mac (BSD) and Linux

后端 未结 13 2080
心在旅途
心在旅途 2020-11-22 08:18

Is there an invocation of sed todo in-place editing without backups that works both on Linux and Mac? While the BSD sed shipped with OS X seems to

相关标签:
13条回答
  • 2020-11-22 08:28

    The -i option is not part of POSIX Sed. A more portable method would be to use Vim in Ex mode:

    ex -sc '%s/alfa/bravo/|x' file
    
    1. % select all lines

    2. s replace

    3. x save and close

    0 讨论(0)
  • 2020-11-22 08:32

    This works with GNU sed, but not on OS X:

    sed -i -e 's/foo/bar/' target.file
    sed -i'' -e 's/foo/bar/' target.file
    

    This works on OS X, but not with GNU sed:

    sed -i '' -e 's/foo/bar/' target.file
    

    On OS X you

    • can't use sed -i -e since the extension of the backup file would be set to -e
    • can't use sed -i'' -e for the same reasons—it needs a space between -i and ''.
    0 讨论(0)
  • 2020-11-22 08:32

    Answer: No.

    The originally accepted answer actually doesn't do what is requested (as noted in the comments). (I found this answer when looking for the reason a file-e was appearing "randomly" in my directories.)

    There is apparently no way of getting sed -i to work consistently on both MacOS and Linuces.

    My recommendation, for what it is worth, is not to update-in-place with sed (which has complex failure modes), but to generate new files and rename them afterwards. In other words: avoid -i.

    0 讨论(0)
  • 2020-11-22 08:33

    You can use sponge. Sponge is an old unix program, found in moreutils package (both in ubuntu and probably debian, and in homebrew in mac).

    It will buffer all the content from the pipe, wait until the pipe is close (probably meaning that the input file is already close) and then overwrite:

    From the man page:

    Synopsis

    sed '...' file | grep '...' | sponge file

    0 讨论(0)
  • 2020-11-22 08:34

    Here's another version that works on Linux and macOS without using eval and without having to delete backup files. It uses Bash arrays for storing the sed parameters, which is cleaner than using eval:

    # Default case for Linux sed, just use "-i"
    sedi=(-i)
    case "$(uname)" in
      # For macOS, use two parameters
      Darwin*) sedi=(-i "")
    esac
    
    # Expand the parameters in the actual call to "sed"
    sed "${sedi[@]}" -e 's/foo/bar/' target.file
    

    This does not create a backup file, neither a file with appended quotes.

    0 讨论(0)
  • 2020-11-22 08:36

    As Noufal Ibrahim asks, why can't you use Perl? Any Mac will have Perl, and there are very few Linux or BSD distributions that don't include some version of Perl in the base system. One of the only environments that might actually lack Perl would be BusyBox (which works like GNU/Linux for -i, except that no backup extension can be specified).

    As ismail recommends,

    Since perl is available everywhere I just do perl -pi -e s,foo,bar,g target.file

    and this seems like a better solution in almost any case than scripts, aliases, or other workarounds to deal with the fundamental incompatibility of sed -i between GNU/Linux and BSD/Mac.

    0 讨论(0)
提交回复
热议问题