包含 AWK 的 CURL 脚本通过 SSH 故障打印 Docker Image Digest

Posted

技术标签:

【中文标题】包含 AWK 的 CURL 脚本通过 SSH 故障打印 Docker Image Digest【英文标题】:CURL script containing AWK fails over SSH to print Docker Image Digest 【发布时间】:2022-01-14 13:21:00 【问题描述】:

以下curl 脚本失败超过ssh

    #!/bin/bash
    reg='dockreg:5000'
    image='mubu6'
    itag='v6'
    auth='-u user:pass'
    accept=(
    -H "Accept: application/vnd.docker.distribution.manifest.v2+json"
    )
    
    ssh -tt root@192.168.122.60 "
    
    echo get digest; read
    curl $auth -vsk \
    -X DELETE \
      "https://$reg/v2/$image/manifests/$(
        curl $auth \
        -vk "$accept[@]" \
        https://$reg/v2/$image/manifests/$itag 2>&1 |\
    grep docker-content-digest | awk 'print $3' |\
    tr -d $'\r'
    )"
    "

不打印digest 在下面第一行的manifests 之后,而在最后一行抛出404 error

DELETE /v2/mubu6/manifests/ HTTP/2
> Host: dockreg:5000
> authorization: Basic YWxleGFuZGVyOnNvZmlhbm9z
> user-agent: curl/7.68.0
> accept: */*
> 
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 404 

在节点上成功运行

echo get digest; read
curl $auth -vsk \
-X DELETE \
  "https://$reg/v2/$image/manifests/$(
    curl $auth \
    -vk "$accept[@]" \
    https://$reg/v2/$image/manifests/$itag 2>&1 |\
grep docker-content-digest | awk 'print $3' |\
tr -d $'\r'
)"

打印第一行manifests之后的digest,最后一行HTTP/2 202 exit code

DELETE /v2/mubu6/manifests/sha256:0aa2280cc066ef4f8279122fc9f76d15e96a8bfa642a54dadbf8c9985f3de747 HTTP/2
> Host: dockreg:5000
> authorization: Basic YWxleGFuZGVyOnNvZmlhbm9z
> user-agent: curl/7.68.0
> accept: */*
> 
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 202 

失败可能与awk 有关,因为它已经需要tr -d $'\r' 才能将line feed 正确传递给curl。 此外,我已经知道awk 不能开箱即用 ssh 只能成功运行以下,转义后 $2 in awk

for x in $NODE_IPS[@]; do
ssh -tt root@$x "
dpkg -l | grep '^rc' | awk 'print \$2' | \
xargs -p dpkg --purge
echo -e "continue to next node \c"; read
"

不幸的是,我的curl 尝试相同的解决方案而不是ssh 脚本抛出错误

awk: cmd. line:1: print \$3
awk: cmd. line:1:        ^ backslash not last character on line
awk: cmd. line:1: print \$3
awk: cmd. line:1:        ^ syntax error

我还在整个脚本中尝试了很多不同的引用排列,但均无济于事。 我对这一切都很陌生,任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

您有三组相互嵌套的双引号。它们对 bash 解析造成了严重破坏。如果您希望将引号内的引号传输到 SSH 隧道的远端,您需要使用反斜杠对其进行转义...

ssh 可能只看到第一组引号内的内容:

ssh -tt root@192.168.122.60 "
    
    echo get digest; read
    curl $auth -vsk \
    -X DELETE \
      "

Bash 有两种引号:单引号和双引号。

单引号将导致 bash 不解释字符串中的任何转义、变量等。

双引号将导致 bash 完全替换转义和变量。

您可以将单引号放在双引号内,变量仍将被替换:

DEMOVAR="just testing"
echo "This is a 'test of $DEMOVAR' to show single quotes have no effect here"

# RESULT:
This is a 'test of just testing' to show single quotes did not affect substitution

但是在单引号里面放双引号的时候就不一样了:

echo 'This is a "test of $DEMOVAR" to show that single quotes prevent substitution'

# RESULT: 
This is a "test of $DEMOVAR" to show that single quotes prevent substitution

为了更复杂,你可以在双引号内“转义”双引号,但不能在单引号内转义单引号:

echo "This set of \"Double quotes\" will show"

但是单引号会连接起来:

echo 'Single quotes \'will not escape\' inside single quotes'

上面的行将打开一个单引号,然后在第一个反斜杠引号之后将其关闭。以下文本:不会在单引号内转义 不在任何引号内,因此第二个反斜杠引号被 bash 转义。最后,行尾的引号打开一个新的 QUOTE 块,因此按 Enter 将等待另一个引号以关闭该块。

困惑???我花了好几年才理解这种细微差别

为了使您的代码更加困难,您将其包装在一个 SSH 中,该 SSH 将内容从第一个双引号传输到第二个双引号,但其余的行并不是真的在双引号内。问题是 bash 替换在哪里完成?您正在尝试使用 $(curl xxxxx) 来获取摘要,但我无法确定您是希望在本地机器上还是在远程机器上。

我建议您将命令分解为多个 SSH 命令以摆脱嵌套:

#!/bin/bash
reg='dockreg:5000'
image='mubu6'
itag='v6'
auth='-u user:pass'
# Note I put double quotes inside single quotes
accept='-H "Accept: application/vnd.docker.distribution.manifest.v2+json"'

# NOT sure what this is:
echo get digest; read

# Get the DIGEST. Note that I got rid of the 'grep'
# as awk can also filter, and I moved the 'tr' before the 'awk'
# I am only doing the 'curl' on the remote machine, and  
# the entire output is transmitted back.  The filters ('tr' and 'awk' )
# are done locally and the DIGEST variable is set locally.

DIGEST=$(ssh root@192.168.122.60 \
    "curl $auth -vk $accept https://$reg/v2/$image/manifests/$itag 2>&1" |\
    tr -d '\r' |awk '/docker-content-digest/ print $3');

# Now call the DELETE with the preset DIGEST.
ssh root@192.168.122.60 \
    "curl $auth -vsk -X DELETE https://$reg/v2/$image/manifests/$DIGEST"

【讨论】:

感谢 DavidG 的提示,我按照你的建议做了,但还是不行。 我用很多细节扩展了答案。嵌套引号和替换时,如果可以避免,最好的建议是不要。使其更易于理解和维护。 是的,这行得通!非常感谢 DavidG 的所有详细解释!

以上是关于包含 AWK 的 CURL 脚本通过 SSH 故障打印 Docker Image Digest的主要内容,如果未能解决你的问题,请参考以下文章

如何在单个 ssh 命令中使用 bash $(awk)?

lvs结合ssh免密做监控,移除故障节点脚本

ssh 登录弹窗提示

shell脚本——awk详细介绍(包含应用案例)

curl: (52) 来自服务器的空回复通过 ssh 端口转发

脚本实例