脚本中字符串的独立于外壳的转义

Dan*_*der 3 shell quoting escape-characters

我只是(再次)为此而挣扎:

# only in bash
NORM=$'\033[0m'
NORM=$'\e[0m'

# only in dash
NORM='\033[0m'

# only in bash and busybox
NORM=$(echo -en '\033[0m')
Run Code Online (Sandbox Code Playgroud)

目标是在字符串中包含特殊字符,不仅用于输出使用echo,还用于管道到 cli 工具等。

在上面的特定用例中,使用$(tput ...)可能是最好的方法,但我要求一个通用的转义解决方案,对外部工具的要求最低,但兼容性最高。

通常,我会使用类似[ -z "$BASH_VERSION" ]但的条件帮助自己

  1. 我还没有找到检测busybox的简单方法
  2. 5 行中的正常变量赋值(使用 if/else/fi)看起来有点矫枉过正
  3. 我更喜欢简单的解决方案

Wil*_*ard 8

你想要的是"$(printf ...)". Stephane 已经写了一篇关于printfvsecho的精彩公开,更多的是一篇文章而不是单纯的答案,所以我不会在这里重复整个事情。与当前问题相关的主旨是:

  1. 坚持POSIX 特性,它非常便携,并且
  2. 它通常是内置的 shell,在这种情况下,您没有外部调用或依赖项。

我还要补充一点,我花了很长时间(好吧,仅仅几个星期)才从 切换到echo,因为我已经习惯echo并认为printf这会很复杂。(所有这些%标志是关于什么的,嗯?)事实证明,printf实际上非常简单,echo除了在末尾带有换行符的固定文本之外,我不再为任何事情而烦恼。


Printf变得简单

有大量的选择printf。您可以将数字打印到精确的特定小数位。您可以打印多个字段,每个字段都具有指定的固定宽度(或最小宽度或最大宽度)。您可以创建一个包含字符序列的 shell 字符串变量,\t或者\n将这些字符序列解释为制表符和换行符来打印。

您可以做所有这些事情,并且您应该知道它们是可能的,以便您可以在需要时查找它们,但在大多数情况下,您只需要了解以下内容:

printf将一个名为“format”的字符串作为它的第一个参数。格式字符串可以指定如何处理进一步的参数(即如何格式化它们)。进一步的参数,如果在格式参数中根本没有引用*,将被忽略

由于字母数字字符(和其他字符)可以嵌入格式参数中并按原样打印,它看起来可能与printf做同样的事情,echo -n但出于某种未知原因,它忽略了除第一个参数之外的所有内容。事实并非如此。

例如,尝试printf some test text。在这个例子some中实际上被当作format,并且因为它不包含任何特殊的东西并且不告诉printf如何处理其余的参数,它们被忽略,你得到的只是some.

%后跟需要在格式字符串中使用的特定字母( 的第一个参数printf)来指定后续参数包含的数据类型。 %s表示“字符串”,是您最常使用的。

\n\t在格式内分别转换为换行符和制表符。

这就是您printf高效使用所需的全部内容。有关一些非常简单的说明性示例,请参阅以下代码块。

$ var1="First"
$ var2="Second"
$ var3="Third"
$ printf "$var1" "$var2" "$var3"       # WRONG
First$                                 # Only the first arg is printed, without a trailing newline
$
$ printf '%s\n' "$var1"                # %s means that the next arg will be formatted as a literal string with any special characters printed exactly as-is.
First
$
$ printf '%s' "$var1" "$var2" "$var3"  # When more args are included than the format calls for, the format string is reused.  This example is equivalent to using '%s%s%s' as the format.
FirstSecondThird$                      # All three args were printed; no trailing newline.
$
$ printf '%s\t%s\t%s\n' "$var1" "$var2" "$var3"
First   Second  Third                  # Tab separation with trailing newline.  This format is very explicit about what to do with three arguments.  Now see what happens if four are used:
$ var4="Fourth"
$ printf '%s\t%s\t%s\n' "$var1" "$var2" "$var3" "$var4"
First   Second  Third             # The specified format is reused after the three expected args,
Fourth                            # so this line has two trailing tabs.
$
$ printf '%s\n' "$var1" "$var2" "$var3"  # This format reuse can be used to advantage in printing a list, for example.
First
Second
Third
$
$ printf '%s\t' "$var1" "$var2" "$var3" ; printf '\n'  # Here is a dual command that could have args added without changing the format string...
First   Second  Third   
$ printf '%s\t' "$var1" "$var2" "$var3" "$var4" ; printf '\n'
First   Second  Third   Fourth              # ...as you can see here.
$                                           # It does print a trailing tab before the newline, however.
Run Code Online (Sandbox Code Playgroud)

* 当然,如果您包含单个参数格式说明符序列,例如%s,您的整个格式字符串将根据需要重复使用多次,以处理提供的所有参数。请参阅示例。