带有 -i 选项的 sed 命令在 Mac 上失败,但在 Linux 上可以运行
- 2024-09-30 14:02:00
- admin 原创
- 155
问题描述:
我已成功使用以下sed
命令在 Linux 中搜索/替换文本:
sed -i 's/old_link/new_link/g' *
然而,当我在 Mac OS X 上尝试时,我得到:
“命令 c 需要 后跟文本”
我以为我的 Mac 运行的是普通的 BASH shell。怎么回事?
编辑:
根据@High Performance,这是由于 Macsed
具有不同的(BSD)风格,所以我的问题是如何在 BSD 中复制此命令sed
?
编辑:
以下是导致此问题的一个实际示例:
sed -i 's/hello/gbye/g' *
解决方案 1:
下面的便携式解决方案
为什么会出现错误
该-i
选项(或者,--in-place
)意味着您希望就地编辑文件,而不是将更改传输到新的位置。
就地修改文件意味着需要备份文件 - 因此之后需要用户指定的扩展名-i
,但在 GNU sed 和 Mac (BSD) sed 下对扩展名参数的解析处理方式不同:
GNU:“如果没有提供扩展名,则原始文件将被覆盖而不进行备份。” - 实际上,您可以完全省略指定文件扩展名。扩展名必须在 之后立即
-i
提供,中间不能有空格。Mac(BSD):“如果给出了零长度的扩展名,则不会保存任何备份。” - 您必须提供扩展名,但如果您愿意,它可以是空字符串“”,以禁用备份。
因此 GNU 和 Mac 会对此有不同的解释:
sed -i 's/hello/bye/g' just_a_file.txt
GNU: 在 之后没有立即提供扩展名
-i
,因此不创建备份,用作s/hello/bye/g
文本编辑命令,并对文件进行just_a_file.txt
就地操作。Mac (BSD):用作
s/hello/bye/g
备份文件扩展名 (!) 和just_a_file.txt
编辑命令 (正则表达式)。
结果:使用的命令代码是j
(不是有效的替换命令代码,例如s
),因此我们得到错误invalid command code j
。
# This still create a `my_file.txt-e` backup on macOS Sonoma (14.5)
# and a `my_file.txt''` on Linux
sed -i'' -e 's/hello/bye/g' my_file.txt
GNU 期望将扩展名立即放在-i
(例如-i''
或-i'.bak'
,没有空格)之后,但 macOS 期望在(例如或)sed
之后有一个空格。-i
`-i ''`-i '.bak'
并且现在也被 Mac (BSD) 所接受sed
,尽管早期版本并不接受它(例如在 Mac OS X v10.6 中,后面需要-i
一个空格,例如-i '.bak'
)。
该-e
参数允许我们明确说明声明编辑命令的位置。
直到 2013 年 Mac OS 更新之前,
仍然没有任何跨 GNU 和 Mac(BSD)的可移植命令,因为这些变体全部失败(出现错误或意外的备份文件):
sed -i -e ...
- 适用于 Linux,但不适用于 macOS,因为它会创建-e
备份sed -i '' -e ...
- 在 macOS 上有效,但在 Linux 上失败sed -i='' -e ...
- 在 macOS 和 Linux 上创建=
备份文件sed -i'' -e ...
- 在 macOS 上创建-e
备份文件并''
在 Linux 上备份
便携式解决方案
您可以通过几种方式在 Linux 和 macOS 上实现相同的结果,例如:
使用 Perl
perl -i -pe's/old_link/new_link/g' *
:。gnu-sed
在 macOS 上使用(使用Homebrew安装)
# Install 'gnu-sed' on macOS using Homebrew
brew install gnu-sed
# Use 'gsed' instead of 'sed' on macOS.
gsed -i'' -e 's/hello/bye/g' my_file.txt
注意:
gnu-sed
在 macOS 上,你可以将包含命令的 bin 路径添加到 PATH 环境变量中,或者为assed
创建别名(将 macOS 替换为 GNU )。最好不要这样做,因为可能有脚本依赖于 macOS 内置版本。gsed
`sedsed
sed`
如果您正在使用sed
脚本,您可以尝试自动切换到gsed
:
#!/usr/bin/env bash
set -Eeuo pipefail
if [[ "$OSTYPE" == "darwin"* ]]; then
# Require gnu-sed.
if ! [ -x "$(command -v gsed)" ]; then
echo "Error: 'gsed' is not istalled." >&2
echo "If you are using Homebrew, install with 'brew install gnu-sed'." >&2
exit 1
fi
SED_CMD=gsed
else
SED_CMD=sed
fi
# Use '${SED_CMD}' instead of 'sed'
${SED_CMD} -i'' -e 's/hello/bye/g' my_file.txt
-i ''
在 macOS 和 BSD 上使用,-i
否则使用(GNU sed)
#!/usr/bin/env bash
set -Eeuo pipefail
case "$OSTYPE" in
darwin*|bsd*)
echo "Using BSD sed style"
sed_no_backup=( -i '' )
;;
*)
echo "Using GNU sed style"
sed_no_backup=( -i )
;;
esac
sed ${sed_no_backup[@]} -e 's/hello/bye/g' my_file.txt
解决方案 2:
我相信在 OS X 上使用 -i 时需要备份文件的扩展名。尝试:
sed -i .bak 's/hello/gbye/g' *
使用 GNUsed
扩展是可选的。
解决方案 3:
在 Mac 中遇到了同样的问题,并使用以下方法解决了brew
:
brew install gnu-sed
并使用
gsed SED_COMMAND
您也可以将其设置sed
为别名gsed
(如果您愿意):
alias sed=gsed
解决方案 4:
这适用于 GNU 和 BSD 版本的 sed:
sed -i'' -e 's/old_link/new_link/g' *
或备份:
sed -i'.bak' -e 's/old_link/new_link/g' *
注意选项后缺少空格-i
!(GNU sed 必需)
解决方案 5:
或者,您可以在 Mac 中安装 sed 的 GNU 版本(称为 gsed),并使用标准 Linux 语法使用它。
为此,请通过运行gsed
来使用 ports 安装(如果您没有,请从<http://www.macports.org/>获取)sudo port install gsed
。然后,您可以运行sed -i 's/old_link/new_link/g' *
解决方案 6:
您的 Mac 确实运行 BASH shell,但这更多的是您正在处理的 sed 的哪个实现的问题。在 Mac 上,sed 来自 BSD,与您在典型的 Linux 机器上看到的 sed 略有不同。我建议您man sed
。
解决方案 7:
Sinetris 的答案是正确的,但我使用这个find
命令来更具体地说明我想要更改哪些文件。一般来说,这应该有效(在 osx 上测试过/bin/bash
):
find . -name "*.smth" -exec sed -i '' 's/text1/text2/g' {} ;
一般来说,在复杂的项目中sed
不使用时find
效率较低。
解决方案 8:
sed
我不会用 来调用 sed./bin/sed
这是我的包装脚本~/project/bin/sed
#!/bin/bash
if [[ "$OSTYPE" == "darwin"* ]]; then
exec "gsed" "$@"
else
exec "sed" "$@"
fi
不要忘记chmod 755
包装脚本。
解决方案 9:
我创建了一个函数来处理sed
MacOS(在 MacOS 10.12 上测试)和其他操作系统之间的差异:
OS=`uname`
# $(replace_in_file pattern file)
function replace_in_file() {
if [ "$OS" = 'Darwin' ]; then
# for MacOS
sed -i '' -e "$1" "$2"
else
# for Linux and Windows
sed -i'' -e "$1" "$2"
fi
}
用法:
$(replace_in_file 's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"',' "./mysql/.env")
在哪里:
,
是分隔符
's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"','
是模式
"./mysql/.env"
是文件路径
解决方案 10:
这是 Bash 脚本中的一个选项:
#!/bin/bash
GO_OS=${GO_OS:-"linux"}
function detect_os {
# Detect the OS name
case "$(uname -s)" in
Darwin)
host_os=darwin
;;
Linux)
host_os=linux
;;
*)
echo "Unsupported host OS. Must be Linux or Mac OS X." >&2
exit 1
;;
esac
GO_OS="${host_os}"
}
detect_os
if [ "${GO_OS}" == "darwin" ]; then
sed -i '' -e ...
else
sed -i -e ...
fi
解决方案 11:
正如其他答案所指出的那样,没有办法在不制作备份文件的情况下在 OS X 和 Linux 之间移植使用 sed。因此,我改用这个 Ruby 单行代码来执行此操作:
ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml
就我而言,我需要从任务中调用它rake
(即在 Ruby 脚本内部),因此我使用了这个额外的引用级别:
sh %q{ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml}
解决方案 12:
以下是如何将环境变量应用于模板文件(无需备份)。
1. 创建带有{{FOO}}的模板以供稍后替换。
echo "Hello {{FOO}}" > foo.conf.tmpl
2. 将 {{FOO}} 替换为 FOO 变量并输出到新的 foo.conf 文件
FOO="world" && sed -e "s/{{FOO}}/$FOO/g" foo.conf.tmpl > foo.conf
适用于macOS 10.12.4和Ubuntu 14.04.5
解决方案 13:
我找到了一个兼容度更高的可移植命令版本sed
,它既适用于 Linux,也适用于 Mac。在某些情况下,例如在package.json
scripts
部分中使用,该命令-i''
在 Mac 上甚至在 Sonoma 版本中也莫名其妙地停止工作,它会抛出错误消息,例如“d 命令末尾有多余的字符”。
诀窍是使用-i=''
而不是-i ''
或-i''
或-i
。这是一个简单的例子:
echo 'ABCD1234' > /tmp/test.txt
sed -i='' -e 's/ABCD/DCBA/g' /tmp/test.txt
cat /tmp/test.txt
Linux 和 Mac 的输出相同DCBA1234
。
解决方案 14:
另一种可移植的方法是使用 Vim 的Ex 模式 ex
:
ex -sc '%s/old/new/g' -c 'x' file
-s
静音模式-c
运行命令
我们传递两个命令:
-c '%s/old/new/g'
* `%`选择所有行
* `s`代替
* `/old/new/`
* `g`替换所有出现的情况
-c 'x'
* `x`保存并退出
请注意,如果文件中不存在该字符串,则简单地传递|x
该字符串会导致编辑器挂起:'%s/old/new/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' {} ;
解决方案 15:
sed -ie 's/old_link/new_link/g' *
使用 gnu sed 可在 BSD 和 Linux 上运行
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件