【问题标题】:Two seemingly identical strings with newlines not equal两个看似相同的字符串,但换行符不相等
【发布时间】:2020-04-30 23:52:53
【问题描述】:

我正在尝试使用 bash 和 sed 将用逗号分隔的带引号的字符串列表转换为由换行符分隔的字符串列表。

这是我正在做的一个例子:

#!/bin/bash

comma_to_newline() {
  sed -En $'s/[ \t]*"([^"]*)",?[ \t]*/\\1\\\n/gp'
}

input='"one","two","three"'
expected="one\ntwo\nthree" 
result="$( echo "${input}" | comma_to_newline )"

echo "Expected: <${expected}>"
echo "Result: <${result}>"

if [ "${result}" = "${expected}" ]; then
  echo "EQUAL!"
else
  echo "NOT EQUAL!"
fi

我得到的输出是:

Expected: <one
two
three>
Result: <one
two
three>
NOT EQUAL!

我知道这与换行符有关,但我不知道是什么。如果我将换行符替换为其他字符串,例如 XXX,它会正常工作,并且 bash 会报告字符串相等。

【问题讨论】:

  • 这就是预期打印输出的结果?不是Expected: &lt;one\ntwo\nthree&gt;
  • 我复制了脚本,我的Expected 同意肖恩的。
  • 是的,这就是我得到的。我正在运行:GNU bash, version 3.2.57(1)-release-(x86_64-apple-darwin18) 在 Mac OS 上。但是在Debian上获得&lt;one\ntwo\nthree&gt; GNU bash, version 5.0.3(1)-release (i686-pc-linux-gnu) ????
  • 我原以为问题出在我的 sed 函数上,但事实证明这是我预期的字符串和旧版本 bash 的问题! expected=$'one\ntwo\nthree' 工作正常!
  • 请注意,您的变量 expected 不包含任何换行符。您可以在设置变量后通过写xxd &lt;&lt;&lt;$expected 来验证这一点。

标签: bash sed newline


【解决方案1】:

在 cmets 关于我的问题的提示下,我设法弄清楚发生了什么。我非常专注于提出一个有效的 sed 表达式并确保 result 是正确的,以至于我没有注意到 expected 字符串不正确。

  1. 要在 bash 字符串中使用 \n 换行符,您必须使用 $'one\ntwo\nthree' 语法 - 有关其他解决方案,请参阅 How can I have a newline in a string in sh?
  2. 我正在针对 bash 版本 3.2.57(Mac OS 10.14.6 附带的版本)进行开发。当使用expected="one\ntwo\nthree" 分配变量然后回显它时,它们在控制台中显示为换行符。较新版本的 bash 将这些字符串显示为转义 - 所以我认为这是一个已在更高版本的 bash 中修复的错误。

【讨论】:

    【解决方案2】:

    为了诊断看似相同的字符串,请尝试将并排的diff 输出与每行一个字符hexdump 格式结合起来。替换:

    else
      echo "NOT EQUAL!"
    fi
    

    ...与:

    else
        echo "NOT EQUAL!"
        diff -y \
        <(hexdump -v  -e '/1  "%_ad#  "' -e '/1 " _%_u\_\n"' <<< "${expected}") \
        <(hexdump -v  -e '/1  "%_ad#  "' -e '/1 " _%_u\_\n"' <<< "${result}")
    fi
    

    【讨论】:

    • 如果涉及奇怪的不可见/ unicode 字符,这将是一个很好的答案。但我的问题原来是因为 bash 打印到标准输出的内容与其内部表示不同。而且我怀疑 Bash 3.2.57 中有一个旧错误。
    • @njh,你似乎已经确定了,所以请考虑answering your own question。关于 "...一个很好的答案 if...":无论哪种方式,这样的答案都有助于测试这样的 "if" 是否是真假。
    【解决方案3】:

    从您的函数返回的字符串中有额外的换行符\n

    八进制转储

    $echo '"one","two","three"' | sed -En $'s/[ \t]*"([^"]*)",?[ \t]*/\\1\\\n/gp' | od -c 
    0000000   o   n   e  \n   t   w   o  \n   t   h   r   e   e  \n  \n
    0000017
    $echo "one\ntwo\nthree"  |  od -c 
    0000000   o   n   e   \   n   t   w   o   \   n   t   h   r   e   e  \n
    0000020
    $
    

    另外,使用echo -e

    $echo "one\ntwo\nthree"  
    one\ntwo\nthree
    $echo -e "one\ntwo\nthree"  
    one
    two
    three
    $
    

    来自man页面

    -e 启用反斜杠转义的解释

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-22
      • 2015-09-25
      • 1970-01-01
      • 2018-04-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多