在bash中为何\n等于'n'?

    str1=\n
    str2='n'

    if [ "$str1" = "$str2" ]; then
        echo "Strings are equal."
    else
        echo "Strings are not equal."
    fi

输出结果
Strings are equal.

在bash中为何\n等于'n'?

阅读 1.4k
avatarAI BotBETA

在bash中,\n 并不等于 'n'。在你的示例中,出现 Strings are equal. 的输出,是因为在bash字符串比较中的特殊行为,但这并不是因为 \n 被解释为 'n'

实际上,当你在bash中设置变量 str1=\n 时,你并没有正确地包含一个换行符(\n),而是仅仅设置了一个名为 str1 的变量,其值为 n(因为反斜杠 \ 在这种情况下没有被正确处理来引入一个特殊的转义字符)。在bash中,要包含换行符,你需要将变量值用双引号括起来,并在反斜杠前使用 $'string' 语法或 echo -e 之类的命令,或者在赋值时确保反斜杠被正确处理(尽管直接在bash变量赋值中处理换行符的常规方法不是使用 \n,而是使用 $'\n' 或通过命令替换等方式)。

然而,在你的示例中,由于 \n 没有被bash解释为换行符,它仅仅被视为普通字符 n 前面的一个普通反斜杠(但由于赋值语法的问题,这里的反斜杠实际上被忽略了),因此 str1 的值最终就是 n。而 str2 显然也是 n,所以两者相等。

如果你的意图是包含换行符,你应该这样做:

str1=$'\n'  # 正确包含换行符
str2='n'

if [ "$str1" = "$str2" ]; then
    echo "Strings are equal."  # 这将不会打印,因为str1包含换行符,而str2是'n'
else
    echo "Strings are not equal."
fi

但请注意,即使这样,上面的比较也不会输出 "Strings are equal.",因为 $str1 实际上包含一个换行符,而 $str2 只是一个字母 n。在bash中直接比较包含特殊字符(如换行符)的字符串时,你需要确保两边的值完全相等。

总结:你的示例中 \n 被错误地解释(或更准确地说,没有被解释)为 n,而不是因为 \n 在bash中“等于”n。正确的换行符表示方式应使用 $'\n'

2 个回答

str1=\n 时,因为这是直接赋值而不是在引号内,bash 会将 \ 视为普通字符的转义,但由于 n 不是一个特殊字符,所以转义实际上是多余的。因此:

  1. str1=\n 实际上等同于 str1=n
  2. str2='n' 就是字母 'n'

所以两个变量最终都只包含字母 'n'。

str1=\n
str2='n'

# 打印各变量的实际内容
echo "str1 is: $str1"  # 输出: str1 is: n
echo "str2 is: $str2"  # 输出: str2 is: n

# 比较
if [ "$str1" = "$str2" ]; then
    echo "Strings are equal."     # 这行会执行
else
    echo "Strings are not equal."
fi

补充

bash 中不同上下文中转义序列的处理方式:

  • 直接赋值时的 \n
  • 双引号中的 "\n"
  • $'' 语法中的 $'\n'

举例

# 1. 直接赋值
str1=\n
echo "直接赋值:"
echo "${str1@Q}"        # 输出: 'n'
echo "长度: ${#str1}"   # 输出: 1

# 2. 双引号
str2="\n"
echo "双引号:"
echo "${str2@Q}"        # 输出: '\n'
echo "长度: ${#str2}"   # 输出: 2

# 3. ANSI-C quoting
str3=$'\n'
echo "ANSI-C quoting:"
echo "${str3@Q}"        # 输出: '\n' (实际是换行符)
echo "长度: ${#str3}"   # 输出: 1

# 实际效果展示
echo "=== 实际打印效果 ==="
echo "str1: $str1"      # 打印: n
echo "str2: $str2"      # 打印: \n
echo -e "str2: $str2"   # 打印一个换行
echo "str3: $str3"      # 直接打印换行

一些常用的 ANSI-C quoting 转义序列:

# 换行符
echo $'\n'  

# 制表符
echo $'\t'  

# 回车符
echo $'\r'  

# 带有八进制值的字符
echo $'\101'  # 打印 'A'

# 带有十六进制值的字符
echo $'\x41'  # 打印 'A'

单引号和双引号在处理转义字符上的区别:

单引号 '...' 不解析转义字符,所有内容按字面量处理。
双引号 "..." 可以解析转义字符(如 \n)。

关键在于赋值时,如果没有用引号括起来,那么反斜杠只会起到续行的作用。
可以运行一下下面这个脚本,会发现和你这里的结果一样。

str1=\ \n
str2=' n'

echo $str1
echo $str2

if [ "$str1" = "$str2" ]; then
    echo "Strings are equal."
else
    echo "Strings are not equal."
fi

要解决你的问题,需要将你的脚本改写成下面这样

str1="\n"
str2='n'

if [ "$str1" = "$str2" ]; then
    echo "Strings are equal."
else
    echo "Strings are not equal."
fi

如果采用单引号括住赋值时的字面量的话,会直接将反斜杠当成单独字符而不是转义字符解析。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏