You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bash脚本中scp批量上传:传入*作为参数失效问题咨询

为什么脚本里用$1传*给scp会失效?

这是个非常典型的Shell路径名展开(globbing)时机问题,我给你一步步拆解清楚:

核心原因:*的展开时机不同

当你直接在命令行执行scp * username2@destination_host:directory2/filename2时,Bash会先帮你把*展开成当前目录下的所有非隐藏文件名,然后把这些文件名作为独立参数传给scp。比如当前目录有file1.txt、file2.jpg,scp实际收到的命令是scp file1.txt file2.jpg username2@host:dir,自然能正常工作。

但当你把*作为参数传给脚本时,会出现两种错误场景:

  1. 没加引号传*:比如运行./your_script * user@host dir,这时候Bash还是会先在脚本外部把*展开成所有文件名,导致$1变成第一个文件名(比如file1.txt),$2变成第二个文件名(file2.jpg),$3才是user@host——这时候你的脚本执行scp $1 $2:$3就变成了scp file1.txt file2.jpg:user@host,完全不符合预期,肯定报错。
  2. 加引号传*:比如运行./your_script "*" user@host dir,这时候Bash不会展开*,$1就是字符串*。scp收到这个参数后,会去本地找名为*的文件,而不是展开成所有文件,自然找不到对应的文件,执行失败。

解决办法

根据你的需求,有两种靠谱的解决方案:

方案1:让脚本接收所有文件参数(推荐)

如果你的需求是上传任意数量的文件(包括用*通配的情况),可以让脚本把除最后两个参数外的所有内容作为要上传的文件,最后两个参数分别是目标主机和目录:

#!/bin/bash
# 提取目标信息:倒数第二个参数是用户@主机,最后一个是目标目录
target_host="${@: -2:1}"
target_dir="${@: -1}"
# 提取要上传的文件:所有参数除了最后两个
files=("${@:1: $#-2}")

# 执行scp,注意用双引号包裹数组,保留带空格的文件名
scp "${files[@]}" "$target_host:$target_dir"

使用方式和直接敲scp一样:

./your_script * username2@destination_host directory2

这时候Bash会先展开*成所有文件,脚本会把这些文件全部传给scp,和直接执行scp命令效果完全一致,还能支持带空格的文件名。

方案2:在脚本内部展开通配符

如果你需要脚本接收通配符字符串(比如用户想上传*.txt这类特定模式的文件),可以在脚本内部手动展开通配符(注意:这种方式要避免处理不可信的参数,防止安全问题):

#!/bin/bash
# 手动展开通配符成文件数组
eval "files=($1)"
# 执行scp
scp "${files[@]}" "$2:$3"

使用时需要给通配符加引号:

./your_script "*.txt" username2@destination_host directory2

内容的提问来源于stack exchange,提问作者Zach

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:35:19