在Linux和Mac上是否都可以调用sed在没有备份的情况下进行就地编辑?虽然OS X附带的BSD sed似乎需要sed -i "…,但GNU sed Linux发行版通常会将引号解释为空的输入文件名(而不是备份扩展名),并且需要sed -i…。

是否有适用于这两种风格的命令行语法,以便我可以在两个系统上使用相同的脚本?


当前回答

下面是另一个在Linux和macOS上工作的版本,无需使用eval,也无需删除备份文件。它使用Bash数组来存储sed参数,这比使用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

这不会创建备份文件,也不会创建带有追加引号的文件。

其他回答

适用于GNU系统和OSX的可移植脚本:

if [[ $(uname) == "Darwin" ]]; then
    SP=" " # Needed for portability with sed
fi

sed -i${SP}'' -e "s/foo/bar/g" -e "s/ping/pong/g" foobar.txt

如果你需要在bash脚本中执行sed in-place,并且你不希望in-place的结果是.bkp文件,并且你有一种方法来检测os(比如,使用ostype.sh),那么下面的bash shell内置eval的hack应该可以工作:

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""`

下面是另一个在Linux和macOS上工作的版本,无需使用eval,也无需删除备份文件。它使用Bash数组来存储sed参数,这比使用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

这不会创建备份文件,也不会创建带有追加引号的文件。

以下是我在Linux和OS X上的工作:

Sed -i' ' <expr> <文件>

例如,对于包含aaabbaaba的文件f

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

在Linux和Mac上生成aaaccaaca。注意,这里有一个带引号的字符串,其中包含一个空格,-i和字符串之间没有空格。单引号和双引号都可以。

在Linux上,我在Ubuntu 14.04.4下使用bash版本4.3.11,在OS X 10.11.4 El Capitan (Darwin 15.4.0)下使用Mac版本3.2.57。

-i选项不是POSIX Sed的一部分。一个更方便的方法是 在Ex模式下使用Vim:

ex -sc '%s/alfa/bravo/|x' file

%选择所有行 年代取代 保存并关闭