使用“while read”时,如何正确格式化传递给远程服务器的“if”语句?

Posted

技术标签:

【中文标题】使用“while read”时,如何正确格式化传递给远程服务器的“if”语句?【英文标题】:How to properly format an 'if' statement being passed to a remote server in a when using 'while read'? 【发布时间】:2020-01-30 13:40:59 【问题描述】:

Ubuntu 18 重击 4.4.0

我想通过 if 语句来查看目录是否存在。如果是这样,我想要一些命令,然后是一个文件。我已经阅读了类似的帖子,但 shellcheck 抱怨我的格式。

脚本:

#!/bin/bash

testing="yes"
scriptDir="/root/.work"
wDir="$scriptDir/.nginx-fix"
if [ "$testing" = "no" ]; then
  hostfile="$scriptDir/.zzz-hostnames"
else
  hostfile="$scriptDir/.zzz-hostnames-tester"
fi

cd "$wDir"
while read fqdn; do
   clear; echo ""; echo ""; echo "$hostname"; echo ""; 
  < /dev/null if ssh -p 34499 root@"$fqdn" '[ -d /etc/nginx ]'; then
    < /dev/null ssh -p 34499 root@"$fqdn" 'mv /etc/nginx/nginx.conf /etc/nginx/.nginx-sept-30'
    < /dev/null scp -P 34499 nginx.conf root@"$fqdn":/etc/nginx
    < /dev/null ssh -p 34499 root@"$fqdn" 'sed -i "/honeypot/d" /etc/nginx/conf.d/*.conf'
    < /dev/null ssh -p 34499 root@"$fqdn" 'nginx -t'
  else
    exit 1;
  fi
done<"$hostfile"

Shellcheck 投诉:

root@me ~/.work/.nginx-fix # shellcheck .nginx-fixer.sh

In .nginx-fixer.sh line 13:
while read fqdn; do
^-- SC1073: Couldn't parse this while loop.
                 ^-- SC1061: Couldn't find 'done' for this 'do'.


In .nginx-fixer.sh line 15:
        < /dev/null if ssh -p 33899 root@"$fqdn" '[ -d /etc/nginx ]'; then
                                                                        ^-- SC1062: Expected 'done' matching previously mentioned 'do'.
                                                                            ^-- SC1072: Expected "#". Fix any mentioned problems and try again.

感谢您的想法。

【问题讨论】:

【参考方案1】:

您可以将脚本重构为更清晰的版本并删除所有&lt;/dev/null

while read -r fqdn; do 
   clear; echo ""; echo ""; echo "$hostname"; echo ""; 
  if ssh -p 34499 root@"$fqdn" '[ -d /etc/nginx ]'; then
    ssh -p 34499 root@"$fqdn" 'mv /etc/nginx/nginx.conf /etc/nginx/.nginx-sept-30'
    scp -P 34499 nginx.conf root@"$fqdn":/etc/nginx
    ssh -p 34499 root@"$fqdn" 'sed -i "/honeypot/d" /etc/nginx/conf.d/*.conf'
    ssh -p 34499 root@"$fqdn" 'nginx -t'
  else
    exit 1;
  fi
 </dev/null; done < "$hostfile"

几乎肉眼看不见,我把所有的命令都放在了do ... done里面 .. &lt;/dev/null里面。这样任何命令都不会从$hostfile 读取,也不会与while read 混淆。

另一种选择是使用专用文件描述符并将其编号传递给读取:

while read -r -u 10 fqdn; do
   clear; echo ""; echo ""; echo "$hostname"; echo ""; 
  if ssh -p 34499 root@"$fqdn" '[ -d /etc/nginx ]'; then
    ssh -p 34499 root@"$fqdn" 'mv /etc/nginx/nginx.conf /etc/nginx/.nginx-sept-30'
    scp -P 34499 nginx.conf root@"$fqdn":/etc/nginx
    ssh -p 34499 root@"$fqdn" 'sed -i "/honeypot/d" /etc/nginx/conf.d/*.conf'
    ssh -p 34499 root@"$fqdn" 'nginx -t'
  else
    exit 1;
  fi
done 10<"$hostfile"

【讨论】:

您的回答得到了很好的解释并教会了我很多东西。非常感谢!【参考方案2】:

通过 'bash -n' 运行脚本将指示“真实”错误:

bash -n x.sh
x.sh: line 15: syntax error near unexpected token `then'
x.sh: line 15: `   < /dev/null if ssh -p 34499 root@"$fqdn" '[ -d /etc/nginx ]' ; then'

您不能在“if”语句之前放置重定向。将重定向移动到 'ssh'(if 的条件部分)命令,例如:

# USE:
if ssh < /dev/null -p 34499 root@"$fqdn" '[ -d /etc/nginx ]' ; then'

# AND NOT:
< /dev/null if ssh -p 34499 root@"$fqdn" '[ -d /etc/nginx ]' ; then'

【讨论】:

您的回答对我来说非常有价值。我知道 sh -x x.sh 用于逐行打印的 shell 脚本,但不知道使用 bash -n x.sh 在 bash 中检查错误。向你致敬,伙计。

以上是关于使用“while read”时,如何正确格式化传递给远程服务器的“if”语句?的主要内容,如果未能解决你的问题,请参考以下文章

linux shell 如何使用while read line去获取一个文件里指定符号前最长的长度

为啥管道输入到“read”只有在输入“while read ...”结构时才有效? [复制]

shell中while read命令的理解

如何以 M/d/yy 格式正确传递给 DatePicker 字符串表示形式的日期

传递字符串对象时使用 apache poi 格式化日期

Linux shell while read line