sed 就地标志,适用于 Mac(BSD)和 Linux [关闭]
- 2024-09-30 15:23:00
- admin 原创
- 98
问题描述:
有没有一种sed
无需备份即可在 Linux 和 Mac 上进行 todo 就地编辑的调用?虽然sed
OS X 附带的 BSD 似乎需要sed -i '' …
,但 GNU sed
Linux 发行版通常会将引号解释为空输入文件名(而不是备份扩展名),而需要sed -i …
。
是否存在适用于这两种版本的命令行语法,以便我可以在两个系统上使用相同的脚本?
解决方案 1:
如果您确实只想使用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
文件。
解决方案 2:
这在 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
由于同样的原因不能使用——和
sed -i'' -e
之间需要一个空格。-i
`''`
解决方案 3:
在 OSX 上时,我总是通过 Homebrew 安装 GNU sed 版本,以避免脚本出现问题,因为大多数脚本都是为 GNU sed 版本编写的。
brew install gnu-sed --with-default-names
那么你的 BSD sed 将被 GNU sed 取代。
或者,您也可以不使用默认名称进行安装,但是:
PATH
安装后按指示更改gnu-sed
请检查你的脚本以选择
gsed
或sed
取决于你的系统
解决方案 4:
正如Noufal Ibrahim所问,为什么不能使用 Perl?任何 Mac 都会有 Perl,而且很少有 Linux 或 BSD 发行版不在基本系统中包括某个版本的 Perl。唯一可能实际上缺少 Perl 的环境之一是 BusyBox(其工作方式与 GNU/Linux 类似-i
,只是不能指定备份扩展)。
正如伊斯梅尔所建议的,
由于 perl 随处可用,因此我只需
perl -pi -e s,foo,bar,g target.file
并且在几乎任何情况下,这似乎都是比脚本、别名或其他解决方法更好的解决方案,可以解决sed -i
GNU/Linux 和 BSD/Mac 之间根本的不兼容性。
解决方案 5:
这是另一个可以在 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
这不会创建备份文件,也不会创建带有附加引号的文件。
解决方案 6:
答:不是。
最初接受的答案实际上并没有满足要求(如评论中所述)。 (我在寻找file-e
目录中“随机”出现的原因时找到了这个答案。)
显然没有办法sed -i
在 MacOS 和 Linuces 上一致地工作。
我的建议是,不要使用 进行就地更新sed
(这具有复杂的故障模式),而是生成新文件并随后重命名。换句话说:避免-i
。
解决方案 7:
没有办法让它工作。
一种方法是使用临时文件,例如:
TMP_FILE=`mktemp /tmp/config.XXXXXXXXXX`
sed -e "s/abc/def/" some/file > $TMP_FILE
mv $TMP_FILE some/file
这对两者都有效
解决方案 8:
该-i
选项不是POSIX Sed的一部分。更便携的方法是在 Ex 模式下使用 Vim:
ex -sc '%s/alfa/bravo/g' -c 'x' file
-s
静音模式-c
运行命令%
选择所有行s
代替/<old>/<new>/
g
`old`替换行中所有出现的
-c
运行命令x
保存并退出
|x
原始答案使用了这样的管道,'%s/alfa/bravo/g|x'
如果文件中不存在字符串,则会导致编辑器挂起:
Error detected while processing command line:
E486: Pattern not found: <old>
使用附加功能-c 'x'
可以解决该问题。
大多数人都希望在 find 命令中找到它,因此这里有一个神奇的咒语:
find . \n -type f \n -exec ex -sc '%s/<old>/<new>/g' -c 'x' {} ;
PS:不要像我一样弄乱你的 git 文件夹:
find . \n -path ./.git -prune -o \n -type f \n -exec ex -sc '%s/<old>/<new>/g' -c 'x' {} ;
解决方案 9:
史蒂夫鲍威尔的回答是相当正确的,查阅OSX和Linux(Ubuntu 12.04)上sed的MAN页面强调了两个操作系统之间“就地”sed使用的不兼容性。
JFYI,使用 Linux 版本的 sed 时,-i 和任何引号(表示空文件扩展名)之间不应该有空格,因此
#Linux
sed -i""
和
#OSX (notice the space after the '-i' argument)
sed -i ""
我在脚本中通过在 bash 'if' 中使用别名命令和 ' uname ' 的 OS 名称输出解决了这个问题。在解释引号时,尝试将依赖于操作系统的命令字符串存储在变量中是碰运气的。为了扩展/使用脚本中定义的别名,必须使用' shopt -s expand_aliases '。shopt 的用法在此处处理。
解决方案 10:
适用于 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
解决方案 11:
如果您需要sed
在脚本中执行就地操作bash
,并且您不希望就地操作产生 .bkp 文件,并且您有办法检测操作系统(例如,使用ostype.sh),那么以下使用bash
shell 内置的hackeval
应该可以工作:
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""`
解决方案 12:
问题是它sed
是一个流编辑器,因此就地编辑是一个非 POSIX 扩展,每个人可能以不同的方式实现它。这意味着对于就地编辑,您应该使用ed
以获得最佳的可移植性。例如
ed -s foobar.txt <<<$',s/foo/bar/g
w'
另请参阅https://wiki.bash-hackers.org/howto/edit-ed。
解决方案 13:
在 macOs 上,你可以使用-e
arg 代替-i
(在 Linux 上)sed -e 's/foo/ar/' src_path > source_path
示例文件内容:python3 /tools/check.py -=some-arg=somevalue
cmd 后的结果sed -e 's//tools/check.py//tools/check.pyc/' example.sh > result.sh
:
python3 /tools/check.pyc -=some-arg=somevalue
另外,> source_path
您不会在标准输出中看到结果。
解决方案 14:
以下内容在 Linux 和 OS X 上对我有用:
sed -i' ' <expr> <file>
f
例如包含以下文件aaabbaaba
sed -i' ' 's/b/c/g' f
在 Linux 和 Mac 上均有效aaaccaaca
。请注意,引号内的字符串包含空格,而和字符串之间没有空格-i
。单引号或双引号均可使用。
在 Linux 上我使用的bash
是 Ubuntu 14.04.4 下的 4.3.11 版本,在 Mac 上我使用的是 OS X 10.11.4 El Capitan(Darwin 15.4.0)下的 3.2.57 版本。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件