我有一个if
语句来计算文件并删除除最新三个文件之外的所有文件。但我想远程运行此命令。我该如何ssh
与if
条件结合?
我尝试过这个,但没有成功。
#!/bin/bash
ssh -t [email protected] "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:没有此文件或目录
答案1
是的,你可以通过以下方式执行复杂的脚本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 [email protected] "$ssh_cmd"
此示例使用 bash这里的文件生成命令字符串。无论如何,通过 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
起作用,因为通配符只发生在本地系统上。另外,使用 来ls
计数文件不是一个好主意,因为它还会返回诸如.
和..
目录之类的条目。
答案2
注意:这里的问题实际上有两个层次。一个是“我想在可通过 SSH 访问的远程服务器上执行一项非平凡任务”。另一个是“我试图将一个复杂的字符串传递给命令,但参数最终与我预期的不同。”我正在回答这个低级问题,而没有讨论所使用的方法是否“正确”(方便、不易出错、安全等)来解决高级问题。正如其他答案和评论所指出的那样,很可能不是。
您的命令行大部分是正确的;您只需稍微改变一下引用。
主要问题是双引号字符串会被本地 shell 扩展,因此这些$(...)
部分将在您的本地系统上进行评估。要将它们传递到远程系统,您必须将脚本括在单引号中。
您还嵌入了一些引号。在您的原始脚本中,有两个 s 的参数echo
;如果您将外部引号更改为单引号,它将是 awk 脚本。这实际上导致省略引号,这不会影响 s echo
,但会弄乱 awk 脚本,因为大于号将成为输出重定向。因此,在将外部引号更改为单引号后,将其更改为双引号。
这是您的脚本,已修复引号。该脚本可能存在其他问题,我只是修复了语法。
#!/bin/bash
ssh -t [email protected] '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'
答案3
我认为整个复杂的引用过程足以证明不要使用它,而要使用脚本。如果您想避免多个
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 [email protected] \
"cat - > /tmp/ms.sh && sh /tmp/ms.sh && rm /tmp/ms.sh"
或者(避免猫的无用用途):
ssh -t [email protected] \
"cat - > /tmp/ms.sh && sh /tmp/ms.sh && rm /tmp/ms.sh" \
< myscript.sh
这会将本地脚本传输myscript.sh
到远程端,在那里将其重定向到(临时)文件/tmp/ms.sh
、执行并最终删除。
注意:我没有检查原始脚本是否有错误,只是想展示这个想法。不需要容易出错的引用,并且脚本中的所有命令都在远程端执行。
答案4
我希望将脚本放在远程实例上并通过 ssh 执行它,但我的建议是如何按照您想要的方式完成此操作:
#!/bin/bash
HOST='[email protected]'
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}
,但我决定添加它们。