情况:我们将文件名列表提供给 sshpass,它会正确地迭代远程文件夹以检查给定名称的文件是否实际存在,然后构建一个仅包含确实存在的文件的更新列表,即稍后在 bash 脚本中重用。
问题:该列表有时包含数以万计的文件,这意味着数以万计的 ssh 登录,这会损害性能,有时还会导致我们被自己的安全策略阻止。
预期的解决方案:不要每次都启动 for 循环并调用 sshpass,而是以其他方式执行并将循环传递给唯一的 sshpass 调用。
我必须将列表传递给下面示例测试中的 sshpass 指令:
#!/bin/bash
all_paths=(`/bin/cat /home/user/filenames_to_be_tested.list`)
existing_paths=()
sshpass -p PASSWORD ssh -n USER@HOST bash -c "'
for (( i=0; i<${#all_paths[@]}; i++ ))
do
echo ${all_paths[i]}
echo \"-->\"$i
if [[ -f ${all_paths[i]} ]]
then
echo ${all_paths[i]}
existing_paths=(${all_paths[i]})
fi
done
'
printf '%s\n' "${existing_paths[@]}"
这里的问题是它似乎循环(您看到一系列回显的行),但最终它并没有真正迭代 i
并且始终检查/打印同一行。
有人可以帮忙发现这个错误吗?谢谢!
最佳答案
问题在于 bash 首先解析字符串并替换变量。这是在发送到服务器之前发生的。如果你想阻止 bash 这样做,你应该转义每个应该在服务器上执行的变量。
#! /bin/bash
all_paths=(rootfs.tar derp a)
read -sp "pass? " PASS
echo
sshpass -p $PASS ssh -n $USER@$SERVER "
files=(${all_paths[@]})
existing_paths=()
for ((i=0; i<\${#files[@]}; i++)); do
echo -n \"\${files[@]} --> \$i\"
if [[ -f \${files[\$i]} ]]; then
echo \${files[\$i]}
existing_paths+=(\${files[\$i]})
else
echo 'Not found'
fi
done
printf '%s\n' \"\${existing_paths[@]}\"
这变得很难快速阅读。然而,有一个我个人喜欢使用的选项。创建函数并将它们导出到服务器以在服务器上执行,从而省略转义大量内容。
#! /bin/bash
all_paths=(rootfs.tar derp a)
function files_exist {
local files=($@)
local found=()
for file in ${files[@]}; do
echo -n "$file --> "
if [[ -f $file ]]; then
echo "exist"
found+=("$file")
else
echo "missing"
fi
done
printf '%s\n' "${found[@]}"
}
read -sp "pass? " PASS
echo
sshpass -p $PASS ssh -n $USER@$SERVER "
$(typeset -f files_exist)
files_exist ${all_paths[@]}
"
关于bash - 如何使用 sshpass 和单个 ssh 登录正确地迭代列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59387553/