繁体   English   中英

sed 就地标志,适用于 Mac (BSD) 和 Linux

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

是否有在 Linux 和 Mac 上都可以使用的不带备份的sed todo 就地编辑的调用? While the BSD sed shipped with OS X seems to need sed -i '' … , the GNU sed Linux distributions usually come with interprets the quotes as empty input file name (instead of the backup extension), and needs sed -i … instead.

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

如果您真的只想以“简单”的方式使用sed -i ,以下内容在 GNU 和 BSD/Mac sed

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

请注意缺少空间和点。

证明:

# 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

显然,您可以删除.bak文件。

这适用于 GNU sed,但不适用于 OS X:

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

这适用于 OS X,但不适用于 GNU sed:

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

在 OS X 上你

  • 不能使用sed -i -e因为备份文件的扩展-e被设置为-e
  • 出于同样的原因,不能使用sed -i'' -e - 它需要-i''之间的空格。

在 OSX 上,我总是通过 Homebrew 安装 GNU sed 版本,以避免脚本出现问题,因为大多数脚本都是为 GNU sed 版本编写的。

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

那么你的 BSD sed 将被 GNU sed 取代。

或者,您可以不使用默认名称进行安装,但是:

  • 安装gnu-sed后按照说明更改PATH
  • 请检查您的脚本以根据您的系统在gsedsed之间进行选择

正如Noufal Ibrahim 所问的,为什么不能使用 Perl? 任何 Mac 都会有 Perl,而且很少有 Linux 或 BSD 发行版在基本系统中不包含某些版本的 Perl。 可能实际上缺少 Perl 的唯一环境之一是 BusyBox(它的工作方式类似于 GNU/Linux for -i ,但不能指定备份扩展名)。

正如伊斯梅尔所建议的那样,

由于 perl 随处可用,我只需执行perl -pi -es,foo,bar,g target.file

几乎在任何情况下,这似乎都是比脚本、别名或其他解决方法更好的解决方案,以处理sed -i在 GNU/Linux 和 BSD/Mac 之间的根本不兼容性。

没有办法让它工作。

一种方法是使用临时文件,如:

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

这适用于

回答:没有

最初接受的答案实际上并没有按照要求执行(如评论中所述)。 (我在寻找file-e在我的目录中“随机”出现的原因时找到了这个答案。)

显然没有办法让sed -i在 MacOS 和 Linuces 上始终如一地工作。

就其价值而言,我的建议不是使用sed (具有复杂的故障模式)就地更新,而是生成新文件并在之后重命名它们。 换句话说:避免-i

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

ex -sc '%s/alfa/bravo/|x' file
  1. %选择所有行

  2. s替换

  3. x保存并关闭

这是另一个适用于 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

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

Steve Powell 的回答非常正确,在 OSX 和 Linux (Ubuntu 12.04) 上查阅 sed 的 MAN 页面强调了两个操作系统中“就地”sed 使用的不兼容性。

JFYI,使用 Linux 版本的 sed 在 -i 和任何引号(表示空文件扩展名)之间不应该有空格,因此

sed Linux 手册页

#Linux
sed -i"" 

sed OSX 手册页

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

我通过使用别名命令和 bash 'if' 中的 ' uname ' 的操作系统名称输出在脚本中解决了这个问题。 在解释引号时,尝试将依赖于操作系统的命令字符串存储在变量中是偶然的。 必须使用“ shopt -s expand_aliases ”才能扩展/使用脚本中定义的别名。 shopt 的用法在这里处理。

适用于 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

我遇到了这个问题。 唯一的快速解决方案是将 mac 中的 sed 替换为 gnu 版本:

brew install gnu-sed

如果您需要在bash脚本中就地执行sed ,并且您不希望就地生成 .bkp 文件,并且您有办法检测操作系统(例如,使用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""`

你可以用海绵。 Sponge 是一个旧的 unix 程序,可以在 moreutils 包中找到(在 ubuntu 和 debian 中,以及在 mac 中的 homebrew 中)。

它将缓冲管道中的所有内容,等到管道关闭(可能意味着输入文件已经关闭)然后覆盖:

手册页

概要

sed '...' 文件 | grep '...' | 海绵文件

问题是sedstream编辑器,因此就地编辑是非 POSIX 扩展,每个人都可能以不同的方式实现它。 这意味着对于就地编辑,您应该使用ed以获得最佳可移植性。 例如

ed -s foobar.txt <<<$',s/foo/bar/g\nw'

另请参阅https://wiki.bash-hackers.org/howto/edit-ed

以下在 Linux 和 OS X 上对我有用:

sed -i' ' <expr> <file>

例如,对于包含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(达尔文 15.4.0)下使用 Mac 版本 3.2.57。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM