将退出状态存储到ssh命令中的变量中

时间:2018-12-11 07:19:06

标签: bash if-statement ssh

我正在尝试检查发送到服务器以更改密码的命令列表中先前命令的状态。当我echo $?时,它可以工作。当我将其存储到STATUS=$?之类的变量中,然后echo $STATUS时,我得到一个空白行。当我将echo $?放入if循环中时,也会返回一些奇怪的东西。以下是ssh命令的代码,以获取有关如何解决此问题的任何建议。

ssh root@192.168.56.13 "printf '%s\n%s' "$PASSWORD" "$PASSCONFIRM" | passwd; STATUS=$?; echo $STATUS; if (( $STATUS == 0 )); then printf 'Password Changed Successfully\n'; else printf 'Password Change Unsuccessful\n'; fi; sleep 1;"
Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully

Password Change Unsuccessful
bash: ((: == 0 : syntax error: operand expected (error token is "== 0 ")

2 个答案:

答案 0 :(得分:2)

您将需要对要在远程服务器中使用的变量进行转义。

$PASSWORD$PASSWORDCONFIRM很好,它们在本地服务器中使用。

然后要在远程服务器中对

$STATUS$?进行评估,因此需要对它们进行替换:STATUS=\$?echo \$STATUSif (( \$STATUS == 0))

答案 1 :(得分:1)

首先,变量引用(例如$STATUS)在命令甚至发送到远程计算机之前就被本地shell扩展了,更不用说执行了。为防止这种情况,您需要转义$(例如\$STATUS),以便将其传递到远程系统,而不是本地解释。

第二,引号不嵌套。您正在尝试将双引号嵌套在双引号字符串中,但这不起作用。您需要转义内部的双引号(就像$一样。)

您可以使用echo代替ssh进行测试。通常,这是一种不好的方式来说明shell命令的操作,因为echo会显示参数经过shell解析过程后 的样子。但是在这种情况下,这正是要发送到远程系统的内容,所以这就是您想要的。这是一个示例:

$ PASSWORD='p4ssw0rd'
$ PASSCONFIRM='p4ssw0rd'
$ echo "printf '%s\n%s' "$PASSWORD" "$PASSCONFIRM" | passwd; STATUS=$?; echo $STATUS; if (( $STATUS == 0 )); then printf 'Password Changed Successfully\n'; else printf 'Password Change Unsuccessful\n'; fi; sleep 1;"
printf '%s\n%s' p4ssw0rd p4ssw0rd | passwd; STATUS=0; echo ; if ((  == 0 )); then printf 'Password Changed Successfully\n'; else printf 'Password Change Unsuccessful\n'; fi; sleep 1;

请注意“ STATUS=0; echo ; if (( == 0 ))”-这是因为所有变量引用($?$STATUS)都在本地扩展,分别扩展为0和“”。这是添加了适当的转义符的版本:

$ echo "printf '%s\n%s' \"$PASSWORD\" \"$PASSCONFIRM\" | passwd; STATUS=\$?; echo \$STATUS; if (( \$STATUS == 0 )); then printf 'Password Changed Successfully\n'; else printf 'Password Change Unsuccessful\n'; fi; sleep 1;"
printf '%s\n%s' "p4ssw0rd" "p4ssw0rd" | passwd; STATUS=$?; echo $STATUS; if (( $STATUS == 0 )); then printf 'Password Changed Successfully\n'; else printf 'Password Change Unsuccessful\n'; fi; sleep 1;

顺便说一句,请注意,我假设PASSWORDPASSCONFIRM是本地的,并且应该在本地扩展,所以我没有逃避$在那些。但是存在潜在的问题:如果两个值中的任何一个都包含在双引号中的内容,则远程外壳对其进行解释。因此,例如,如果您的密码是p4$$w0rd,则$$将被远程Shell的进程ID代替。在它们周围使用单引号会更好,但是如果它们包含单引号,则会导致混乱:

$ PASSWORD="p4'\$\$w0rd"
$ echo "$PASSWORD"    # show the true password
p4'$$w0rd
$
$ # This will not work right, because of the $$:
$ echo "printf '%s\n%s' \"$PASSWORD\" \"$PASSCONFIRM\" ..."
printf '%s\n%s' "p4'$$w0rd" "p4ssw0rd" ...
$
$ # Neither will this, because of the single-quote:
$ echo "printf '%s\n%s' '$PASSWORD' '$PASSCONFIRM' ..."
printf '%s\n%s' 'p4'$$w0rd' 'p4ssw0rd' ...
$
$ # But this, while messy, will work:
$ ESCAPEDPW=${PASSWORD//\'/\'\\\'\'}
$ ESCAPEDCONFIRM=${PASSCONFIRM//\'/\'\\\'\'}
$ echo "printf '%s\n%s' '$ESCAPEDPW' '$ESCAPEDCONFIRM' ..."
printf '%s\n%s' 'p4'\''$$w0rd' 'p4ssw0rd' ...

...等等,我听到你说,会起作用吗?是的,这是该密码混乱将在远程系统上执行的演示:

$ printf '%s\n%s' 'p4'\''$$w0rd' 'p4ssw0rd'
p4'$$w0rd
p4ssw0rd

(请注意,它们不匹配,因为我没有费心更新PASSCONFIRM。)