linux中我要写一个sh脚本把recv文件夹里面的*_rjh.txt的文件都复制到远程服务器127.0.0.1的rab文件夹中,并将文件移动到同级目录下的bak中,使用expect命令写
时间: 2025-08-02 13:29:53 浏览: 17
<think>我们面临的任务:编写一个sh脚本,使用expect命令实现以下功能:1.将本地recv文件夹中所有以"_rjh.txt"结尾的文件通过scp传输到远程服务器127.0.0.1的rab文件夹中。2.传输完成后,将recv文件夹中的这些文件移动到本地的bak备份目录。注意:使用expect命令是为了自动输入scp过程中可能需要的密码(避免交互式输入)。步骤分解:1.我们需要一个expect脚本,用于处理scp传输的自动交互(包括可能出现的yes/no提示和密码输入)。2.在sh脚本中,我们需要遍历recv文件夹中所有匹配的文件,对每个文件调用expect脚本进行传输。3.传输成功后,将文件移动到bak目录。考虑到可能有多个文件,我们可以用一个循环来处理每个文件。参考引用[4]和[5]中提供的expect脚本示例,我们可以编写一个类似的expect脚本。我们将编写两个文件:-一个expect脚本(比如叫scp_expect.exp)用于执行单个文件的scp传输。-一个sh脚本(比如叫transfer.sh)用于遍历文件并调用expect脚本,然后移动文件。首先,编写expect脚本(scp_expect.exp):该脚本需要接收参数:远程主机、用户名、密码、源文件路径、目标路径。注意:由于我们要传输的是文件,所以不需要递归选项(-r),除非要传输目录。但题目要求是文件,所以去掉-r。其次,在sh脚本中:遍历recv目录下的所有*_rjh.txt文件,对每个文件:调用expect脚本(scp_expect.exp)传输该文件到远程服务器。如果传输成功(我们可以通过expect的返回值判断),则将该文件移动到bak目录。注意:在expect脚本中,我们使用spawn来启动scp进程,然后根据提示输入响应。由于scp在第一次连接时可能会提示是否保存主机密钥(yes/no),所以我们在expect脚本中需要处理两种情况。根据引用[4]中的示例,我们可以这样写expect脚本:```expect#!/usr/bin/expect-fsetHOST[lindex$argv0]setUSERNAME[lindex$argv1]setPASSWD[lindex$argv2]setsource_file[lindex$argv3]settarget_dir[lindex$argv4]spawnscp$source_file$USERNAME@$HOST:$target_direxpect{"yes/no"{send"yes\r"exp_continue}"password:"{send"$PASSWD\r"}}expecteof```但是,注意:可能同时出现多个expect匹配,所以使用exp_continue来继续等待。另外,如果已经发送过yes,那么接下来就会要求输入密码。然而,上面的脚本有一个问题:在发送yes之后,会再次进入expect块,因为发送完yes后,服务器会再次提示输入密码。所以我们可以调整一下:引用[4]中的写法是:```expectexpect{"(yes/no)?"{send"yes\n"expect"*assword:"{send"$PASSWD\r"}}"*assword:"{send"$PASSWD\r"}}```我们采用类似的方式:修改后的expect脚本(scp_expect.exp):```expect#!/usr/bin/expect-fsetHOST[lindex$argv0]setUSERNAME[lindex$argv1]setPASSWD[lindex$argv2]setsource_file[lindex$argv3]settarget_dir[lindex$argv4]spawnscp$source_file$USERNAME@$HOST:$target_direxpect{"yes/no"{send"yes\r"exp_continue}"*assword:"{send"$PASSWD\r"}timeout{send_user"Connectiontimedout\n"exit1}}expecteof#检查scp的退出状态catchwaitresultsetexit_status[lindex$result3]exit$exit_status```注意:我们添加了超时处理,并且最后通过捕获scp的退出状态来返回给调用者(sh脚本)以判断是否成功。然后,编写sh脚本(transfer.sh):我们需要设置远程服务器的信息(主机、用户名、密码),以及本地目录和备份目录。然后遍历recv目录下的所有符合条件的文件,对每个文件执行:调用expect脚本进行传输如果传输成功(expect脚本返回0),则移动该文件到bak目录注意:确保bak目录存在,如果不存在则创建。具体sh脚本如下:```sh#!/bin/sh#设置远程服务器信息REMOTE_HOST="127.0.0.1"REMOTE_USER="your_username"#替换为你的远程服务器用户名REMOTE_PASS="your_password"#替换为你的远程服务器密码REMOTE_DIR="rab"#远程目标目录#本地目录设置LOCAL_RECV_DIR="recv"#本地存放待传输文件的目录LOCAL_BAK_DIR="bak"#本地备份目录#确保备份目录存在mkdir-p"$LOCAL_BAK_DIR"#遍历recv目录下所有以_rjh.txt结尾的文件forfilein"$LOCAL_RECV_DIR"/*_rjh.txt;do#如果找不到匹配的文件,循环会执行一次(此时file等于"recv/*_rjh.txt"),所以需要检查文件是否存在if[!-f"$file"];thencontinuefiecho"Transferring$fileto$REMOTE_HOST..."#调用expect脚本传输文件./scp_expect.exp"$REMOTE_HOST""$REMOTE_USER""$REMOTE_PASS""$file""$REMOTE_DIR"#检查上一条命令的退出状态if[$?-eq0];thenecho"Transfersuccessful.Moving$filetobackupdirectory."mv"$file""$LOCAL_BAK_DIR/"elseecho"Transferfailedfor$file.Itwillnotbemovedtobackup."fidoneecho"Allfilesprocessed."```注意:将expect脚本和sh脚本放在同一目录下,并给expect脚本执行权限:chmod+xscp_expect.exp另外,在sh脚本中,我们假设expect脚本的名字是scp_expect.exp,并且与sh脚本在同一目录。使用注意事项:1.请替换sh脚本中的REMOTE_USER和REMOTE_PASS为实际的用户名和密码。2.确保远程服务器上目标目录(rab)存在,并且有写入权限。3.确保本地目录结构正确(recv和bak目录)。安全提示:在脚本中直接写入密码可能不安全,可以考虑使用其他安全方式(如ssh密钥认证)来避免密码明文存储。但根据题目要求,我们使用expect自动输入密码。如果希望更安全,可以考虑使用ssh密钥认证,这样就不需要密码了。但本题要求使用expect和密码。另外,如果远程服务器已经添加过公钥(即不会出现yes/no提示),那么expect脚本中处理yes/no的部分就不会触发。如果出现传输失败,文件不会移动到备份目录,这样可以避免文件丢失。以上脚本仅供参考,请根据实际环境测试调整。现在,根据要求生成相关问题。</think>### 实现文件传输与备份的脚本方案
下面是一个完整的 Shell 脚本解决方案,使用 `expect` 命令实现将 `recv` 文件夹中的 `*_rjh.txt` 文件传输到远程服务器,并自动备份到本地 `bak` 目录。
```sh
#!/bin/bash
# 配置参数
REMOTE_HOST="127.0.0.1"
REMOTE_USER="your_username" # 替换为远程服务器用户名
REMOTE_PASS="your_password" # 替换为远程服务器密码
REMOTE_DIR="rab" # 远程目标目录
LOCAL_RECV_DIR="recv" # 本地源文件目录
LOCAL_BAK_DIR="bak" # 本地备份目录
# 确保备份目录存在
mkdir -p "$LOCAL_BAK_DIR"
# 遍历recv目录中的目标文件
for file in "$LOCAL_RECV_DIR"/*_rjh.txt; do
# 跳过不存在的文件
[ -e "$file" ] || continue
echo "处理文件: $(basename "$file")"
# 使用expect自动执行SCP传输
/usr/bin/expect <<EOF
set timeout 30
spawn scp "$file" $REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/
expect {
"yes/no" {
send "yes\r"
exp_continue
}
"password:" {
send "$REMOTE_PASS\r"
}
timeout {
send_user "\n连接超时\n"
exit 1
}
}
expect eof
EOF
# 检查传输状态
if [ $? -eq 0 ]; then
echo "传输成功,移动文件到备份目录"
mv "$file" "$LOCAL_BAK_DIR/"
else
echo "传输失败,保留文件在原位置"
fi
done
echo "所有文件处理完成"
```
### 使用说明
1. **脚本准备**:
- 将脚本保存为 `transfer_files.sh`
- 修改脚本开头的配置参数:
- `REMOTE_USER`:远程服务器用户名
- `REMOTE_PASS`:远程服务器密码
- `REMOTE_DIR`:远程目标路径(默认为 `rab`)
- 给脚本添加执行权限:
```bash
chmod +x transfer_files.sh
```
2. **目录结构**:
```
./
├── transfer_files.sh # 主脚本
├── recv/ # 存放待传输文件
│ └── *_rjh.txt # 目标文件
└── bak/ # 备份目录(脚本会自动创建)
```
3. **执行脚本**:
```bash
./transfer_files.sh
```
### 脚本工作流程
1. **遍历源文件**:
- 自动扫描 `recv` 目录中所有 `*_rjh.txt` 文件
- 跳过不存在的文件(防止空匹配)
2. **自动传输**:
- 使用 `expect` 处理 `scp` 的交互过程:
- 自动应答首次连接的 `yes/no` 确认
- 自动输入密码完成认证
- 设置 30 秒超时防止卡死
3. **备份处理**:
- 传输成功后:将文件移动到 `bak` 目录
- 传输失败时:保留文件并提示错误
4. **错误处理**:
- 连接超时自动终止
- 返回非零状态码表示失败
- 保留失败文件避免数据丢失
### 安全建议
1. **密码安全**:
- 实际使用建议配置 SSH 密钥认证,避免密码明文存储
- 生成密钥对:`ssh-keygen -t rsa`
- 部署公钥:`ssh-copy-id [email protected]`
2. **权限管理**:
```bash
chmod 700 transfer_files.sh # 限制脚本访问权限
chmod -R 700 recv bak # 限制目录访问权限
```
3. **日志增强**(可选):
在 `expect` 块前添加:
```bash
echo "$(date) 传输文件: $(basename "$file")" >> transfer.log
```
> **注意事项**:首次连接新服务器时,SCP 会询问主机认证,脚本已自动处理 `yes/no` 确认。如果服务器指纹变更会导致认证失败,需手动更新 `~/.ssh/known_hosts` 文件[^4][^5]。
阅读全文
相关推荐















