我正在运行Ubuntu 16.04.5 LTS。我有以下脚本:
#!/bin/bash
set -x
for i in "$@"; do
echo $i
done
运行它,我得到:
$ scripts/t.sh a b c\\nd
+ for i in "$@"
+ echo a
a
+ for i in "$@"
+ echo b
b
+ for i in "$@"
+ echo 'c\nd'
c\nd
如果我将shebang更改为#!/bin/sh
,然后重新运行,则会得到:
$ scripts/t.sh a b c\\nd
+ set -x
+ echo a
a
+ echo b
b
+ echo c\nd
c
d
在bash情况下,换行符显示为set -x
日志中的引号,而echo
不解释换行符;使用sh
时,该值显示为不带引号,并且解释换行符。这是预期的吗?为什么会有所不同?
答案 0 :(得分:4)
set -x
输出中的差异 POSIX不需要set -x
来显示以任何特定方式引用的输出。来自matendie:
在扩展命令之后和执行命令之前,外壳程序应将每个命令的跟踪信息写入标准错误。尚未确定是否跟踪了关闭跟踪的命令。
...并且在the POSIX specification for the set
command中,PS4
的定义如下:
在交互式外壳中执行执行跟踪(
set -x
)时,应在执行跟踪的每一行之前对该变量的值进行参数扩展,并写入标准错误。默认值为“ +”。 POSIX.1-2017的此卷仅针对支持“用户可移植性实用程序”选项的系统指定了变量的作用。
“ A trace”(跟踪)或“ the trace”(用于指定PS4
之后的文本的唯一语言)含糊不清,以至于两个实现都同样兼容。
echo
输出中的差异 POSIX echo
总是 遵守转义序列,而无需传递-e
。 (实际上,不允许完全兼容POSIX的echo
将-e
视为要打印的文本以外的任何其他内容,因此bash违反了规范-除非当同时启用xpg_echo
和posix
运行时标志时,这是bash的echo
唯一听见标准字母的情况。
如果您希望跨平台保持一致的行为,请使用printf '%s\n' "$foo"
而不是echo "$foo"
。
完整引用the shell command language specification的APPLICATION USAGE部分,并强调:
除非所有{IX}(作为第一个参数)和转义序列都被省略,否则不可能在所有POSIX系统上可移植地使用
echo
。
-n
实用程序可用于如下模拟printf
实用程序的任何传统行为(假设echo
具有其标准值或未设置):>
此版本的POSIX.1-2017中具有历史意义的系统V
IFS
和XSI实现的要求等效于:echo
BSD
printf "%b\n" "$*"
等效于:echo
鼓励新应用使用
if [ "X$1" = "X-n" ] then shift printf "%s" "$*" else printf "%s\n" "$*" fi
而不是printf
。
出于上面引用的粗体语言的目的,序列echo
是一个“转义序列”。