求助:通过SSH运行携带本地文件参数的本地脚本遇问题
解决SSH远程执行脚本时传递本地文件参数的问题
我来帮你拆解下当前遇到的问题,然后给出几个可行的解决方案:
原脚本的核心问题分析
你当前的写法:
ssh -o ConnectTimeout=5 -i ./private_key as@$line < ./mod_users.sh "$1" "$2"
存在两个关键问题:
"./mod_users.sh"通过标准输入传递给SSH,远程机器会执行这个脚本,但后面的"$1"和"$2"是本地Shell解析的参数——远程机器拿到的只是本地的$1值和本地文件名($2),但远程机器上根本没有这个本地文件,所以脚本执行时会报错找不到文件。- SSH的标准输入已经被
./mod_users.sh占用了,没办法同时把本地文件的内容传递给远程脚本。
解决方案1:先上传文件到远程,再执行脚本(最可靠,适合大文件)
这种方法的思路是先用scp把本地文件传到远程机器的临时目录,然后让远程脚本使用这个远程路径作为参数,执行完成后可以删除临时文件。修改后的脚本如下:
#!/bin/bash if [ $# -ne 3 ] then echo "Incorrect number of parameters" exit 1 fi # 定义本地文件路径和远程临时文件路径 LOCAL_FILE="$2" REMOTE_TEMP_FILE="/tmp/$(basename "$LOCAL_FILE")" cat "$3" | while read line; do # 第一步:上传本地文件到远程临时目录 scp -o ConnectTimeout=5 -i ./private_key "$LOCAL_FILE" as@$line:"$REMOTE_TEMP_FILE" if [ $? -ne 0 ]; then echo "$line: Failed to upload local file" continue fi # 第二步:远程执行脚本,传入参数和远程临时文件路径 ssh -o ConnectTimeout=5 -i ./private_key as@$line "./mod_users.sh" "$1" "$REMOTE_TEMP_FILE" if [ $? -ne 0 ]; then echo "$line: Failed to access or script execution failed" else # 可选:脚本执行成功后删除远程临时文件 ssh -o ConnectTimeout=5 -i ./private_key as@$line "rm -f $REMOTE_TEMP_FILE" fi done
优点:
- 适合任何大小的文件,不会因为内容特殊字符出问题
- 逻辑清晰,排查问题简单
解决方案2:把文件内容作为参数传递(适合小文件)
如果你的本地文件内容不大,且没有太多特殊字符(比如换行、引号),可以直接把文件内容读入变量,作为参数传递给远程脚本:
#!/bin/bash if [ $# -ne 3 ] then echo "Incorrect number of parameters" exit 1 fi # 读取本地文件内容到变量 FILE_CONTENT=$(cat "$2") cat "$3" | while read line; do # 把文件内容作为参数传递给远程脚本 ssh -o ConnectTimeout=5 -i ./private_key as@$line "./mod_users.sh" "$1" "$FILE_CONTENT" if [ $? -ne 0 ]; then echo "$line is not accessible or script failed" fi done
注意事项:
- 如果文件包含特殊字符(比如换行、双引号、反斜杠),可能会导致参数解析错误,这时候可以用
base64编码来避免:# 本地编码文件内容 FILE_CONTENT=$(base64 "$2") # 远程脚本里需要解码使用: # echo "$2" | base64 -d > temp_file
解决方案3:通过SSH多路复用优化性能(可选)
如果你的目标机器很多,每次SSH和SCP都建立新连接会很慢,可以开启SSH多路复用,复用同一个连接来传输文件和执行命令,提升效率:
在脚本开头添加以下配置(或者写在~/.ssh/config里):
# 开启SSH连接复用 SSH_OPTIONS="-o ConnectTimeout=5 -i ./private_key -o ControlMaster=auto -o ControlPath=/tmp/ssh-%r@%h:%p -o ControlPersist=60s"
然后后续的scp和ssh都使用$SSH_OPTIONS:
scp $SSH_OPTIONS "$LOCAL_FILE" as@$line:"$REMOTE_TEMP_FILE" ssh $SSH_OPTIONS as@$line "./mod_users.sh" "$1" "$REMOTE_TEMP_FILE"
这样所有针对同一机器的操作都会复用同一个SSH连接,节省连接建立的时间。
内容的提问来源于stack exchange,提问作者Enrique Torres
相关产品推荐
相关产品推荐

