SSH如何处理if条件?


8

我有一条if声明来计算文件并删除除最新的三个文件以外的所有文件。但是我想远程运行此命令。我怎样才能结合sshif条件?

我尝试了这个但没有成功。

#!/bin/bash

ssh -t  test@192.168.94.139 "cd /var/www/test.com/backup ;

if [ $(ls  | wc -l) -lt 3  ]
then
    echo "Less"
else [ $(ls -t *.tgz|awk 'NR >3'|xargs rm -f) ]
    echo "deleted"
fi"

我得到的错误:

ls:无法访问* .tgz:没有此类文件或目录


那我该如何自定义呢?
Janith '18

@ user68186为什么?该命令用引号引起来。
轻轨赛将于

2
$( )命令的一部分由本地Shell执行,甚至没有启动ssh命令。无论是$( )单独放置还是被"s 包围都是如此。但是,如果$( )'s 内部,则不会由本地shell执行。
kasperd

Answers:


3

注意:实际上,这里的问题有两层。一个是“我想在可通过SSH访问的远程服务器上执行一项重要任务”。另一个是“我试图将复杂的字符串传递给命令,并且参数最终与我的意图不同。” 我在回答低级问题,而没有讨论解决高级问题所使用的方法是否“正确”(方便,不易出错,安全等)。正如其他答案和评论所指出的那样,事实并非如此。

您的命令行大部分是正确的;您只需要稍稍更改报价即可。

主要问题是,双引号引起来的字符串由本地外壳扩展,因此这些$(...)部分将在本地系统上求值。要将它们传递到远程系统,必须将脚本用单引号引起来。

您也有一些嵌入的引号。在原始脚本中,有两个参数echo。如果将外部引号更改为单引号,它将是awk脚本。这些有效地导致省略了引号,这不会打扰echos,但是它将使awk脚本混乱,因为大于号将变为输出重定向。因此,在将外部引号更改为单引号后,将其更改为双引号。

这是带引号固定的脚本。该脚本可能还有其他问题,我只是修复了语法。

#!/bin/bash

ssh -t  test@192.168.94.139 'cd /var/www/test.com/backup ;

if [ $(ls  | wc -l) -lt 3  ]
then
  echo "Less"
else [ $(ls -t *.tgz|awk "NR >3"|xargs rm -f) ]
  echo "deleted"
fi'

我想分配给/var/www/test.com/backup一个名为“ BACKUPDEST”的变量,cd $BACKUPDEST您能告诉我该怎么做吗?
Janith

1
您将值分配到BACKUPDEST哪里?如果在远程发生这种情况,请正常地将其包括在脚本中。如果要在本地设置它(例如,在本地脚本中计算它,或将其作为命令行参数传递给它),则可以将第一行更改为例如"cd $BACKUPDEST"' ;-shell扩展双引号部分,保留单引号完整无缺的部分,将两者串联起来,并将结果作为最后一个参数传递给ssh
pt314 '18 / 12/4

嗯,"cd '$BACKUPDEST'"' ;以防万一该变量中的路径包含一些奇怪的地方(例如空格)。再说一次:只是说可以这样做,而不是应该这样做。
pt314 '18 / 12/4

10

是的,您可以通过以下方式执行复杂的脚本 ssh

#!/bin/bash -e

ssh_cmd="$(cat <<-EOF
    cd /var/www/test.com/backup;

    if [ \$(ls  | wc -l) -lt 3  ]; then
        echo "less"
    elif [ \$(ls -t *.tgz|awk 'NR >3'|xargs rm -f) ]; then
        echo "deleted"
    else
        echo "something else"
    fi
EOF
)"

ssh -t test@192.168.94.139 "$ssh_cmd"

本示例使用bash here文档生成命令字符串。无论如何,通过ssh传递脚本都是容易出错的,因为变量的引用和转义很困难(在命令前加反斜杠)。如果脚本太复杂,最好通过复制它scp,然后在目标主机上执行它。

我没有尝试修复您的脚本,但以下示例说明了如何在远程主机上进行计数和删除:

#!/bin/bash -e

tmp_dir="$(mktemp -d)"

ssh_cmd="$(cat <<-EOF
    cd "$tmp_dir"

    cnt_tgz=(\$(find . -type f -name "*.tgz"))
    if [[ \${#cnt_tgz[@]} -lt 3 ]]; then
        echo "less"
    else
        rm "\${cnt_tgz[@]}"
        echo "deleted"
    fi
EOF
)"

touch "$tmp_dir/1.tgz"
ssh -t localhost "$ssh_cmd"
touch "$tmp_dir/2.tgz" "$tmp_dir/3.tgz"
ssh -t localhost "$ssh_cmd"

该操作ls -t *.tgz将不起作用,因为仅在本地系统上发生了globing。还使用ls计数文件是不是一个好主意,因为它也返回条目一样...和目录。


我有一些错误。 syntax error near unexpected token elif'elif [ $(ls -t |awk 'NR >3'|xargs rm -f) ]; then'
Janith '18

有一个;在拳if语句丢失。但是我没有解决您的脚本!还有更多问题,例如ls *.tgz
Simon Sudler

1
“ ls -t * .tgz将不起作用,因为该错误仅发生在本地系统上。” -如果正确地转义,它将在远程系统上发生。原始版本$(...)在双引号字符串内没有任何内容,因此本地外壳对其进行了评估。\$(...)如您在第一个示例中所示转义,或在整个脚本中使用单引号,以防止本地外壳扩展它,因此它被发送到远程系统,由远程外壳扩展,并且脚本可以工作如预期。
pt314 '18 / 12/3

在这种情况下,我强烈建议使用单引号而不是here文档。即使您要插入一些变量,最好还是使用单引号引起来的字符串并printf扩展变量-与尝试对所有shell变量进行转义相比,这将更易于管理。同样,它将避免cat只需要将here文档捕获到变量中!
丹尼尔·普瑞登

4

我认为这整个复杂的引用材料足以证明不使用它,而是使用脚本。如果要避免多个 ssh连接,请将脚本通过管道传递到另一台主机,然后在一个命令中在该主机上运行:

本地文件,说myscript.sh

cd /var/www/test.com/backup;

if [ $(ls  | wc -l) -lt 3  ]; then
    echo "less"
elif [ $(ls -t *.tgz|awk 'NR >3'|xargs rm -f) ]; then
    echo "deleted"
else
    echo "something else"
fi

然后:

cat myscript.sh | \
    ssh -t test@192.168.94.139 \
    "cat - > /tmp/ms.sh && sh /tmp/ms.sh && rm /tmp/ms.sh"

或(避免无用的使用猫):

ssh -t test@192.168.94.139 \
    "cat - > /tmp/ms.sh && sh /tmp/ms.sh && rm /tmp/ms.sh" \
    < myscript.sh

myscript.sh会将本地脚本通过管道传输到远程端,在本地将其重定向到(临时)文件/tmp/ms.sh,执行并最终删除。

注意:我没有检查原始脚本是否有错误,只是想展示这个想法。不需要容易出错的引用,脚本中的所有命令都在远程执行。


也无需将脚本保存到临时文件中,只需将其通过管道传输到合适的shell中即可ssh user@host bash <myscript.sh
pt314 '18 / 12/3

2
不过请记住,重定向仅在脚本本身不尝试从标准输入中读取时才有效。
chepner

@ pt314是,但是请参阅将脚本
PerlDuck

是的,重定向有其局限性。它还避免了与写入(然后执行)可预测名称的临时文件相关的一堆安全问题。如果您确实使用了临时脚本(无论是出于选择还是必要),请使用mktemp或类似的安全脚本来创建它。
pt314

3

我希望将脚本放置在远程实例上,然后通过ssh来执行它,但是这是我的建议,该如何以您想要的方式完成:

#!/bin/bash

HOST='test@192.168.94.139'
REMOTE_PATH='/var/www/test.com/backup'

COMMAND1="ssh \"$HOST\" 'ls \"$REMOTE_PATH\" | wc -l'"
COMMAND2="ssh \"$HOST\" 'ls -t \"$REMOTE_PATH\"/*.tgz'"
COMMAND3="xargs ssh \"$HOST\" rm -rf"

if [[ $(eval "$COMMAND1") -le 3 ]]
then
    echo "Less"
else
    eval "$COMMAND2" | awk 'NR > 3' | eval "$COMMAND3" && echo "Deleted"
fi

笔记:

  • 条件表达式-lt被替换-le
  • eval -通过串联参数构造命令。
  • 我不知道我们是否真的需要这些额外的报价单\"的范围内$COMMAND{1..3}表达,但我决定加入他们。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.