【问题标题】:Weird behavior on bash variablesbash 变量的奇怪行为
【发布时间】:2017-08-06 01:45:43
【问题描述】:

我有以下情况,我尝试使用以下脚本来访问我的脚本之一中指定 SSH 端口上的 jenkins 环境。

但是由于某种原因,该变量与该变量有一些奇怪的行为。

回显变量时,它看起来很正常。 在字符串中回显变量时,除非它位于字符串的末尾,否则不会显示它 在 ssh 命令中使用变量时,它会弄乱整个 ssh 命令。

我错过了什么?我可以做些什么来进一步排除故障?

$ ssh_port=$(curl -vsL http://localhost/login 2>&1 | grep 'X-SSH-Endpoint' | cut -d':' -f 3)
$ echo $ssh_port
44149
$ echo "${ssh_port} jenkins port"
 jenkins port
$ echo "Jenkins port ${ssh_port}"
Jenkins port 44149
$ ssh -p $ssh_port localhost
'ad port '44149

更新:

按照 cmets 中的建议,我尝试使用 2 个命令进行故障排除。

$ printf %s "$ssh_port" | xxd
00000000: 3434 3134 390d                           44149.
$ od -c <<<"$ssh_port"
0000000   4   4   1   4   9  \r  \n
0000007

有什么方法可以在没有这些奇怪字符的情况下实现我想要的吗?

【问题讨论】:

  • 您的变量中可能包含\r。使用declare -p ssh_port
  • ...如果declare 的输出看起来很乱,那么这就是建议回车的更多证据。您也可以使用 od -c &lt;&lt;&lt;"$ssh_port" 来显示变量中的字符。
  • printf %s "$ssh_port" | xxd 也可以提供帮助...
  • 你可以在参数扩展中去掉\r,虽然它不是很明显:"${ssh_port//$'\r'}"(或者,要删除 CR+LF 对,"${ssh_port//$'\r\n'}")。
  • 请参阅bash tag wiki 获取有关处理 DOS 行尾(CRLF,也用作网络协议的一部分)的建议。

标签: linux bash jenkins ssh environment-variables


【解决方案1】:

您已确认变量内有回车。

在 bash 或任何支持 ANSI C(格式)扩展的 POSIX shell 中,您可以像这样轻松解决这个问题:

$ ssh_port=$'44149\r'
$ od -c <<<"$ssh_port"
0000000    4   4   1   4   9  \r  \n
0000007
$ new_port="${ssh_port%$'\r'}"
$ od -c <<<"$new_port"
0000000    4   4   1   4   9  \n
0000006

${variable%text} 扩展为 $variable 的内容,去掉了字符串末尾的 text$'\r' 当然是换行符。

您也可以删除填充变量的管道中的回车:

$ ssh_port=$(curl -vsL http://localhost/login 2>&1 | tr -d '\r' | sed -ne 's/^X-SSH-Endpoint: [^:]*://p')

甚至,

$ read ssh_port < <(curl -vsL http://localhost/login 2>&1 | grep '^X-SSH-Endpoint:' | grep -E -o '[0-9]+')

最后,单独的参数扩展可以隔离行的数字部分:

$ while read t; do [[ $t == X-SSH-Endpoint:* ]] && ssh_port="${t//[^0-9]/}" && break; done < <(curl -vsL http://localhost/login 2>&1)

或者,如果您想将标头及其值视为单独的变量,并允许主机名包含数字:

$ while read h v; do [[ $h == X-SSH-Endpoint: ]] && { v="${v#*:}"; ssh_port="${v//[^0-9]/}"; break; }; done < <(printf 'one\r\n%s\nthree\r\n' "$s")

这么多选择。 :-)

【讨论】:

    【解决方案2】:

    你可以试试

    ssh_port=$(curl -vsL http://localhost/login 2>&1 | sed '
        /X-SSH-Endpoint/!d         # replace grep
        s/\r$//                    # remove line ending CR
        s/.*://                    # remove up to last colon
    ')
    

    【讨论】:

    • 这给了我一个空值。
    • 好的,现在它向我展示了 Grep 已经向我展示的全部内容,而没有我使用 cut -d':' 所做的事情:'
    • 早上太早了。最后一个模式中有一个额外的星号
    • 如果人们没有注意到问题上的linux 标签,最好指出这个解决方案依赖于 GNU sed,并且在 BSD 或 macOS 中不起作用。
    • 这里的 GNU 是什么?
    猜你喜欢
    • 2015-09-15
    • 2016-06-01
    • 2011-12-05
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 2014-06-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多