包含 AWK 的 CURL 脚本无法通过 SSH 打印 Docker Image Digest

CURL script containing AWK fails over SSH to print Docker Image Digest

以下 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 }' |\
    tr -d $'\r'
    )"
    "

不打印 在下面第一个输出行 manifests 之后的 digest,同时在最后一个输出行上抛出 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 }' |\
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 仅从 运行 成功以下 awk 中转义 </code> 后:</p> <pre><code>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 "

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

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

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

你有三组相互嵌套的双引号。他们正在对 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

为了让它更复杂,你可以 'escape' 双引号里面的双引号,但是你不能在单引号里面转义单引号:

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

但是单引号会连接起来:

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

以上行将打开一个单引号,然后在第一个反斜杠引号后立即将其关闭。以下文本: will not escape' inside single quotes is not inside any quotes 因此第二个反斜杠引号被 [=49= 转义].最后,行尾的报价 OPENS 一个新的 QUOTE 块 因此按回车键将等待另一个报价关闭该块。

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

为了使您的代码更加困难,您将其包装在 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 }');

# 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}"