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

后端 未结 13 2081
心在旅途
心在旅途 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:39

    If you need to do sed in-place in a bash script, and you do NOT want the in-place to result with .bkp files, and you have a way to detect the os (say, using ostype.sh), -- then the following hack with the bash shell built-in eval should work:

    OSTYPE="$(bash ostype.sh)"
    
    cat > myfile.txt <<"EOF"
    1111
    2222
    EOF
    
    if [ "$OSTYPE" == "osx" ]; then
      ISED='-i ""'
    else # $OSTYPE == linux64
      ISED='-i""'
    fi
    
    eval sed $ISED 's/2222/bbbb/g' myfile.txt
    ls 
    # GNU and OSX: still only myfile.txt there
    
    cat myfile.txt
    # GNU and OSX: both print:
    # 1111
    # bbbb
    
    # NOTE: 
    # if you just use `sed $ISED 's/2222/bbbb/g' myfile.txt` without `eval`,
    # then you will get a backup file with quotations in the file name, 
    # - that is, `myfile.txt""`
    
    0 讨论(0)
  • 2020-11-22 08:39

    The following works for me on Linux and OS X:

    sed -i' ' <expr> <file>

    e.g. for a file f containing aaabbaaba

    sed -i' ' 's/b/c/g' f

    yields aaaccaaca on both Linux and Mac. Note there is a quoted string containing a space, with no space between the -i and the string. Single or double quotes both work.

    On Linux I am using bash version 4.3.11 under Ubuntu 14.04.4 and on the Mac version 3.2.57 under OS X 10.11.4 El Capitan (Darwin 15.4.0).

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

    There is no way to have it working.

    One way is to use a temporary file like:

    TMP_FILE=`mktemp /tmp/config.XXXXXXXXXX`
    sed -e "s/abc/def/" some/file > $TMP_FILE
    mv $TMP_FILE some/file
    

    This works on both

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

    If you really want to just use sed -i the 'easy' way, the following DOES work on both GNU and BSD/Mac sed:

    sed -i.bak 's/foo/bar/' filename
    

    Note the lack of space and the dot.

    Proof:

    # GNU sed
    % sed --version | head -1
    GNU sed version 4.2.1
    % echo 'foo' > file
    % sed -i.bak 's/foo/bar/' ./file
    % ls
    file  file.bak
    % cat ./file
    bar
    
    # BSD sed
    % sed --version 2>&1 | head -1
    sed: illegal option -- -
    % echo 'foo' > file
    % sed -i.bak 's/foo/bar/' ./file
    % ls
    file  file.bak
    % cat ./file
    bar
    

    Obviously you could then just delete the .bak files.

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

    When on OSX, I always install GNU sed version via Homebrew, to avoid problems in scripts, because most scripts were written for GNU sed versions.

    brew install gnu-sed --with-default-names
    

    Then your BSD sed will be replaced by GNU sed.

    Alternatively, you can install without default-names, but then:

    • Change your PATH as instructed after installing gnu-sed
    • Do check in your scripts to chose between gsed or sed depending on your system
    0 讨论(0)
  • 2020-11-22 08:49

    Steve Powell's answer is quite correct, consulting the MAN page for sed on OSX and Linux (Ubuntu 12.04) highlights the in-compatibility within 'in-place' sed usage across the two operating systems.

    JFYI, there should be no space between the -i and any quotes (which denote an empty file extension) using the Linux version of sed, thus

    sed Linux Man Page

    #Linux
    sed -i"" 
    

    and

    sed OSX Man page

    #OSX (notice the space after the '-i' argument)
    sed -i "" 
    

    I got round this in a script by using an alias'd command and the OS-name output of 'uname' within a bash 'if'. Trying to store OS-dependant command strings in variables was hit and miss when interpreting the quotes. The use of 'shopt -s expand_aliases' is necessary in order to expand/use the aliases defined within your script. shopt's usage is dealt with here.

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