有没有办法让 bash (版本 3.2.57(1),如果重要的话)在模拟 sh 的模式下实现内置-n
选项echo
?
具体来说,我很好奇是否可以在某处设置一个选项,而不是echo -n
在 M 个不同的脚本中寻找并重写 N 个调用,而这些选项多年来一直运行良好(也许只是运气不好)。显然 bash 的内置函数可以echo
实现-n
,因为在完整的 bash 模式下,它确实可以实现。
[免责声明:是的,我知道这echo -n
首先是不可移植的,但printf
建议这样做。]
旁注:评论者指出这个版本的 bash 已经“17 岁了”。有人应该告诉 Apple 这件事——这是我在相当新的 Mac 上随 MacOS Ventura 13.0 附带的版本。
答案1
我能想到的最好的主意是用GNU coreutils 中的echo
“真正的”echo
可执行文件替换内置函数,如果你有 bash,几乎肯定会安装它:
echo() { "$(type -P echo)" "$@" ; }
它只是隐藏了内置的。
由于 GNU Coreutilecho.c
确实不是很长,其中很大一部分是特殊情况处理,例如“我在 UNIX System V 上运行并且预计会有这样的行为吗?”、--help
打印和类似的事情严格地如果需要,您可以考虑在您的 shell 脚本中包含一个小的 C 实现,echo
并通过 POSIX 指定的方式将其放入(c99
如果您知道自己已经实现了)。哎呀,这是一台 2000 年代的机器,所以您不妨假设您有 Perl 并在 Perl 中实现相同的功能。
答案2
正如所见为什么 printf 比 echo 更好?, 当同时启用该选项(例如作为 调用时)并且启用该选项(因为默认情况下在构建 bash 以便与 UNIX 兼容的系统上)时,bash
不支持该-n
选项(也不支持-e
/ -E
) 。posix
sh
xpg_echo
因此,要获得 bash 的echo
支持-n
(和-e
/-E
及其组合,例如echo -en
,echo -e -n
...),您需要禁用其中一个或两个选项。如果您希望sh
除此之外仍然兼容 UNIX -n
,则可能xpg_echo
只需将其关闭:
shopt -u xpg_echo
例子:
$ bash -o posix -O xpg_echo -c 'echo -n a'
-n a
$ bash -o posix -O xpg_echo -c 'shopt -u xpg_echo; echo -n a'
a
bash 仍然大部分与 UNIX 兼容,除了-n
未打印的内容。
$ bash -o posix -O xpg_echo -c 'set +o posix; echo -n a'
a
启用了该-n
处理,但也启用了一些其他非 UNIX 合规性,因此它的行为更不像标准sh
.
答案3
我的 Mac 上的外部设备/bin/echo
确实支持-n
,您可以使用以下命令禁用 Bash 内置功能enable -n
:
bash-3.2$ enable -n echo
bash-3.2$ type echo
echo is /bin/echo
bash-3.2$ echo -n foo |od -c
0000000 f o o
0000003
答案4
解决根本问题
如果您使用“升级 bash macOS”作为搜索词,Google 将返回大量结果。使用本地交换答案,并将 2 个答案合并为一个(根据您的旁注):
当人们分发包含 GPLv3 下的软件的用户产品时,第 6 节要求他们向您提供修改该软件所需的信息。用户产品是许可证中专门定义的术语;用户产品的示例包括便携式音乐播放器、数字录像机和家庭安全系统。
由于Apple的Darwin OS从10.5左右开始就已经闭源,提供升级的BASH将违反上述段落,因此Apple确实知道。有一种方法可以更新 BASH shell,甚至将其设为默认 shell:
通过 Homebrew 安装更新的 Bash
将以下内容粘贴到您的终端中:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
作为一行。- 问题
brew install bash
这应该在 Homebrew 中安装 BASH 的更新版本,然后进行符号链接。用于which bash
查找位置 要将其设置为默认位置:
- 编辑
/etc/shells
。 - 将路径+二进制文件添加到文件末尾。
- 注销并重新登录以更新您的环境。
- 使用
chsh
命令“Change Shells”,提供新 BASH 版本的路径。这应该使新版本成为您的默认 shell。