D25
一: 普通变量和环境变量和特殊变量:
在Linux中,`.`(点号)和`source`是等价的命令,它们都用于在当前Shell会话中执行脚本或加载配置文件,而不是在新的子进程中运行。这样可以让脚本中定义的环境变量、函数等在当前会话中生效。
关于加载`/etc/profile`,这是一个系统级的Shell配置文件,通常用于设置全局环境变量和启动时的Shell行为(比如PATH、umask等)。下面我详细解释一下`.`或`source`加载`/etc/profile`的用法和作用:
### 用法
```bash
. /etc/profile
```
或者
```bash
source /etc/profile
```
### 作用
1. **执行并应用环境变量**:
`/etc/profile`通常包含全局的环境变量设置,比如`PATH`、`LANG`等。用`.`或`source`加载后,这些变量会立刻在当前Shell会话中生效,而不是只在脚本运行的子进程中临时生效。
2. **更新当前会话**:
如果你修改了`/etc/profile`(比如添加了新的PATH路径),直接运行`bash /etc/profile`只会影响新开的子Shell,而当前Shell不会受影响。用`.`或`source`则可以让当前会话立即应用这些更改。
### 举个例子
假设`/etc/profile`里有一行:
```bash
export MY_VAR="Hello, Linux!"
```
你在终端输入:
```bash
source /etc/profile
```
然后运行:
```bash
echo $MY_VAR
```
输出会是:
```
Hello, Linux!
```
如果不用`source`而是直接`bash /etc/profile`,`MY_VAR`不会在当前会话中生效。
### 注意事项
1. **权限**:
普通用户可以加载`/etc/profile`,但如果里面有需要root权限的操作(比如修改系统级的设置),可能不会有预期效果。
2. **适用Shell**:
`/etc/profile`通常是为Bourne Shell兼容的Shell(如bash、sh)设计的。如果用的是zsh或fish这样的非兼容Shell,可能需要加载对应的配置文件(比如`~/.zshrc`)。
3. **重复加载**:
多次加载`/etc/profile`一般不会有什么问题,但如果里面有复杂的脚本逻辑(比如追加PATH),可能会导致重复定义,得看具体内容。
### 实际场景
- 你刚改了`/etc/profile`里的`PATH`,想马上用新路径?用`source /etc/profile`。
- 想临时测试`/etc/profile`的设置?直接`.`或`source`就行。
在Linux中,变量是Shell编程和系统配置的核心部分。它们可以用来存储数据、定义环境行为等。以下我将详细讲解Linux中的变量命名规则、分类,以及你提到的环境变量`$LANG`、`$PS1`和`$PATH`。
---
### 一、Linux变量命名规则
1. **合法字符**:
- 变量名必须以字母(A-Z,a-z)或下划线(_)开头。
- 后续字符可以是字母、数字(0-9)或下划线。
- 不允许使用空格、特殊字符(如@、#、$)作为变量名的一部分。
2. **大小写敏感**:
- `MY_VAR`和`my_var`是两个不同的变量。
3. **命名约定**:
- 通常用全大写表示环境变量或全局变量(比如`PATH`)。
- 小写或驼峰式命名(`myVar`)常用于脚本中的局部变量。
- 避免使用保留关键字(如`if`、`for`)作为变量名。
示例:
```bash
MY_VAR=123 # 合法
_var2="test" # 合法
2var="no" # 非法,数字开头
my var="hi" # 非法,包含空格
```
---
### 二、变量分类
Linux中的变量可以根据作用域和用途分为以下几类:
1. **局部变量**:
- 只在当前Shell脚本或函数中有效。
- 定义方式:直接赋值。
- 示例:
```bash
my_var="hello"
echo $my_var
```
- 在脚本结束后,`my_var`不会影响父Shell。
2. **环境变量**:
- 通过`export`命令导出的变量,可被子进程继承。
- 常用于配置系统或程序的行为。
- 示例:
```bash
export MY_ENV="world"
bash # 进入子Shell
echo $MY_ENV # 输出 "world"
```
3. **Shell内置变量**:
- Shell预定义的变量,用于特定用途,比如`$HOME`、`$PWD`。
- 示例:
```bash
echo $HOME # 输出用户主目录,如 "/home/user"
```
4. **只读变量**:
- 用`readonly`或`declare -r`定义,不能修改。
- 示例:
```bash
readonly CONST="fixed"
CONST="new" # 会报错
```
5. **位置参数变量**:
- 用于脚本参数,如`$1`、`$2`表示脚本的第一个、第二个参数。
- 示例:
```bash
# 脚本 test.sh
echo "First arg: $1"
# 调用:bash test.sh hello
# 输出:First arg: hello
```
6. **特殊变量**:
- 如`$?`(上个命令退出状态)、`$$`(当前进程ID)。
- 示例:
```bash
ls /not_exist
echo $? # 输出非0值,表示失败
```
---
### 三、常见环境变量解析
你提到的`$LANG`、`$PS1`和`$PATH`是Linux中非常重要的环境变量,以下是它们的详细说明:
#### 1. `$LANG`
- **作用**:定义系统的语言和区域设置(locale),影响字符编码、时间格式等。
- **常见值**:
- `en_US.UTF-8`:美国英语,UTF-8编码。
- `zh_CN.UTF-8`:简体中文,UTF-8编码。
- **用法**:
```bash
echo $LANG # 查看当前语言
export LANG="zh_CN.UTF-8" # 设置为中文
```
- **影响**:比如`ls`命令的输出语言、错误信息的语言。
#### 2. `$PS1`
- **作用**:定义Shell提示符的外观(Prompt String 1)。
- **常见值**:
- 默认可能是`\u@\h:\w\$`,表示“用户名@主机名:当前目录$”。
- 示例:`user@linux:/home$`
- **自定义**:
```bash
PS1='\[\e[32m\]\u@\h:\w\$\[\e[0m\] ' # 绿色提示符
```
- `\u`:用户名
- `\h`:主机名
- `\w`:当前工作目录
- `\$`:普通用户显示`$`,root显示`#`
- **查看**:
```bash
echo "$PS1"
```
#### 3. `$PATH`
- **作用**:定义可执行文件的搜索路径,Shell会按顺序在这些目录中查找命令。
- **默认值**(示例):
- `/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin`
- **用法**:
- 查看:
```bash
echo $PATH
```
- 添加路径:
```bash
export PATH=$PATH:/my/new/path
```
- **影响**:如果某个命令不在`$PATH`中,运行时会报“command not found”。
---
### 四、实战示例
假设你想设置一个中文环境并自定义提示符:
```bash
export LANG="zh_CN.UTF-8"
export PS1="[\u@\h \w]\$ "
export PATH="$PATH:/usr/local/mybin"
```
运行后:
- 提示符变成 `[user@host /home/user]$`
- 系统语言变为中文
- 命令搜索路径多了`/usr/local/mybin`
---
其他: echo ${week}_day
在Linux中,UID(User ID)是一个环境变量,表示当前用户的ID。root用户的UID始终是0。我们可以用Shell脚本通过检查$UID来判断当前用户是否为root。下面我给你几个实现方法,从简单到复杂,方便你选择使用。
方法一:简单判断
bash
WrapCopy
#!/bin/bash if [ "$UID" -eq 0 ]; then echo "你是root用户!" else echo "你不是root用户,UID是:$UID" fi
- 解释:
- $UID:当前用户的ID。
- -eq:等于(用于整数比较)。
- 如果$UID等于0,说明是root。
方法二:更健壮的写法
考虑到某些环境可能未正确设置$UID,可以用id -u命令(返回当前用户的UID)作为备用:
bash
WrapCopy
#!/bin/bash uid=$(id -u) if [ "$uid" -eq 0 ]; then echo "你是root用户!" else echo "你不是root用户,UID是:$uid" fi
- 解释:
- id -u:直接获取当前用户的UID,比依赖$UID更可靠。
- 把结果存到变量uid中再判断。
二: Linux Bash 脚本,可以显示主机名、IP 地址、总计内存、可用内存和系统负载,并按照你指定的格式输出:
方法2
下面是一个简单的 Linux Bash 脚本,可以显示主机名、IP 地址、总计内存、可用内存和系统负载,并按照你指定的格式输出:
```bash
#!/bin/bash
# 获取主机名
hostname=$(hostname)
# 获取第一个网络接口的 IP 地址(通常是 eth0 或 enp0s3,排除回环地址)
ip_address=$(ip addr show | grep -oE 'inet [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | grep -v '127.0.0.1' | awk '{print $2}' | head -n 1)
# 获取总计内存(以 MB 为单位)
total_memory=$(free -m | awk '/^Mem:/{print $2}')
# 获取可用内存(以 MB 为单位)
available_memory=$(free -m | awk '/^Mem:/{print $7}')
# 获取系统负载(1分钟平均负载)
system_load=$(uptime | awk -F 'load average:' '{print $2}' | cut -d, -f1 | tr -d ' ')
# 输出指定格式的内容
echo "主机名: $hostname"
echo "地址: $ip_address"
echo "总计内存: ${total_memory}MB"
echo "可用内存: ${available_memory}MB"
echo "系统负载: $system_load"
```
### 脚本说明:
1. **主机名**:使用 `hostname` 命令获取。
2. **地址**:通过 `ip addr show` 获取第一个非回环的 IP 地址。
3. **总计内存和可用内存**:使用 `free -m` 命令以 MB 为单位获取内存信息。
4. **系统负载**:从 `uptime` 中提取 1 分钟的平均负载。
### 使用方法:
1. 将上述代码保存到一个文件,例如 `system_info.sh`。
2. 赋予执行权限:
```bash
chmod +x system_info.sh
```
3. 运行脚本:
```bash
./system_info.sh
```
### 示例输出:
```
主机名: my-server
地址: 192.168.1.100
总计内存: 8192MB
可用内存: 5432MB
系统负载: 0.25
```
三: 特殊变量 `$n`、`$0`、`$#` 和 `$@ $?
在 Shell 编程中(特别是 Bash),`$n`、`$0`、`$#` 和 `$@` 是常用的特殊变量,用于处理脚本的参数。下面是对它们的详细解析:
---
### 1. `$n`(位置参数)
- **定义**: `$n` 表示传递给脚本或函数的第 `n` 个参数,其中 `n` 是一个数字。
- `$1` 是第一个参数。
- `$2` 是第二个参数。
- 以此类推,`$3`、`$4` 等依次表示后续参数。
- **用法**: 当脚本接收命令行参数时,可以通过 `$n` 访问这些参数。
- **示例**:
```bash
#!/bin/bash
echo "第一个参数: $1"
echo "第二个参数: $2"
```
运行 `./script.sh hello world`,输出:
```
第一个参数: hello
第二个参数: world
```
- **注意**: 如果 `n` 超过实际参数数量,结果为空。
---
### 2. `$0`(脚本名称)
- **定义**: `$0` 表示脚本本身的名称(包括路径,取决于调用方式)。
- **用法**: 常用于提示用户脚本名称或在脚本中自我引用。
- **示例**:
```bash
#!/bin/bash
echo "脚本名称: $0"
```
如果脚本名为 `test.sh`,运行 `./test.sh`,输出:
```
脚本名称: ./test.sh
```
- **注意**: `$0` 的值取决于调用脚本的方式:
- `./test.sh` 输出 `./test.sh`。
- `/full/path/test.sh` 输出完整路径。
- `bash test.sh` 输出 `test.sh`。
---
### 3. `$#`(参数个数)
- **定义**: `$#` 表示传递给脚本或函数的参数总数(不包括 `$0`)。
- **用法**: 用于检查脚本是否接收到预期数量的参数。
- **示例**:
```bash
#!/bin/bash
echo "参数总数: $#"
```
运行 `./script.sh a b c`,输出:
```
参数总数: 3
```
- **注意**: 如果没有传递参数,`$#` 为 `0`。
---
### 4. `$@`(所有参数的列表)
- **定义**: `$@` 表示所有传递给脚本或函数的参数,以单独的字符串形式保存。
- **用法**: 通常用于遍历所有参数,或者将参数传递给其他命令。
- **特点**:
- 与 `$*` 类似,但区别在于 `$@` 在被双引号 `"$@"` 包裹时,会保留每个参数的独立性(即空格分隔的完整参数)。
- **示例**:
```bash
#!/bin/bash
echo "所有参数: $@"
for arg in "$@"; do
echo "参数: $arg"
done
```
运行 `./script.sh "hello world" foo bar`,输出:
```
所有参数: hello world foo bar
参数: hello world
参数: foo
参数: bar
```
- **注意**:
- 如果不加双引号(即直接用 `$@`),效果类似于 `$*`,可能会丢失参数的边界。
- 双引号 `"$@"` 是推荐用法,尤其是处理带空格的参数时。
---
### `$@` vs `$*`(补充说明)
- `$*`: 将所有参数视为一个整体字符串,用 `$IFS`(默认是空格)连接。
- `$@`: 将所有参数视为独立的字符串数组。
- **示例对比**:
```bash
#!/bin/bash
echo "用 \$*: $*"
echo "用 \$@: $@"
```
运行 `./script.sh "hello world" foo`,输出:
```
用 $*: hello world foo
用 $@: hello world foo
```
但用循环时:
```bash
for i in "$*"; do echo $i; done
for i in "$@"; do echo $i; done
```
输出:
```
hello world foo # $*: 一个整体
hello world # $@: 分别处理
foo
```
---
### 综合示例
以下是一个综合使用这些变量的脚本:
```bash
#!/bin/bash
echo "脚本名称: $0"
echo "参数总数: $#"
echo "第一个参数: $1"
echo "第二个参数: $2"
echo "所有参数: $@"
if [ $# -eq 0 ]; then
echo "错误:请提供至少一个参数!"
exit 1
fi
for param in "$@"; do
echo "处理参数: $param"
done
```
运行 `./script.sh one "two three" four`,输出:
```
脚本名称: ./script.sh
参数总数: 3
第一个参数: one
第二个参数: two three
所有参数: one two three four
处理参数: one
处理参数: two three
处理参数: four
```
---
### 总结
- `$n`: 第 `n` 个参数(`$1`, `$2`, ...)。
- `$0`: 脚本名称。
- `$#`: 参数数量。
- `$@`: 所有参数的列表(推荐用 `"$@"` 保留参数完整性)。
在 Linux/Unix 的 shell 脚本中,$? 是一个特殊的变量,它用于获取上一个执行命令的退出状态码(exit status)。理解 $? 的用法对于编写健壮的 shell 脚本至关重要。
基本概念:
- 退出状态码:
- 每个在 Linux 中执行的命令都会返回一个退出状态码,用来表明命令执行的结果。
- 按照惯例,退出状态码为
0表示命令成功执行。 - 任何非零的退出状态码都表示命令执行过程中出现了错误。
- 不同的非零值可能代表不同类型的错误。
$?变量:$?变量会保存上一个执行命令的退出状态码。- 你可以通过访问
$?变量的值来判断上一个命令是否成功执行。
常见用法:
- 检查命令是否成功:
Bash
command # 执行某个命令
if [ $? -eq 0 ]; then
echo "命令成功执行"
else
echo "命令执行失败,退出状态码为:$?"
fi
- 在这个例子中,
$?被用来检查command是否成功执行。 [ $? -eq 0 ],代表判断变量“$?”的值是否等于0,等于0则代表上一条命令执行成功。
- 在脚本中处理错误:
Bash
if grep "pattern" file.txt; then
echo "找到了匹配的行"
else
echo "没有找到匹配的行"
fi
grep命令在找到匹配的行时返回0,否则返回非零值。- 通过
if语句,可以根据grep的返回值来执行不同的操作。
- 链式命令执行:
Bash
command1 && command2
&&运算符表示只有command1成功执行(返回0)时,才会执行command2。- 这是一种简洁的写法,用于确保只有在前一个命令成功时才执行下一个命令。
重要注意事项:
$?的值会在每次执行新命令后立即更新。- 因此,如果你想保存某个命令的退出状态码,需要立即将其赋值给另一个变量。
总结:
$? 变量是 shell 脚本中一个非常有用的工具,它允许你根据命令的执行结果来控制脚本的流程,并处理可能出现的错误。通过合理地使用 $?,你可以编写出更加健壮和可靠的 shell 脚本。
判断指定用户是否存在。
id $user >/dev/null 2>&1 是一个常用的 Linux shell 命令,让我们逐步解析它的含义:
1. id $user:
id是一个 Linux 命令,用于显示用户的身份信息,包括用户 ID (UID)、用户组 ID (GID) 等。$user是一个变量,代表要检查的用户名。例如,如果$user的值为 "john",那么命令就会变成id john。- 如果用户存在,
id命令会输出该用户的身份信息。 - 如果用户不存在,
id命令会输出错误信息。
2. >/dev/null:
>是输出重定向符号,用于将命令的输出重定向到指定的文件或设备。/dev/null是一个特殊的设备文件,它会丢弃所有写入其中的数据。- 因此,
>/dev/null的作用是将id命令的标准输出(即用户的身份信息)丢弃,不显示在终端上。
3. 2>&1:
2是标准错误文件描述符,代表错误输出。1是标准输出文件描述符,代表正常输出。>&1的作用是将标准错误重定向到标准输出。- 结合前面的
>/dev/null,2>&1的作用就是将id命令的错误输出(即用户不存在时的错误信息)也丢弃,不显示在终端上。
综合解释:
- 整个命令
id $user >/dev/null 2>&1的作用是:执行id命令检查用户是否存在,并将所有输出(包括正常输出和错误输出)都丢弃。 - 这样做的目的是为了在脚本中静默地判断用户是否存在,而不产生任何输出。
- 判断用户是否存在通常会配合判断上一条命令是否执行成功,也就是判断返回代码是否为0,如果为0则代表命令执行成功,也就是用户存在,反之用户则不存在。
- 通常会配合“$?”来判断上一条命令是否执行成功。
实际应用:
- 在 shell 脚本中,可以使用这个命令来判断用户是否存在,然后根据判断结果执行不同的操作。
- 例如,可以这样写一个简单的脚本:
Bash
#!/bin/bash
user="testuser"
id $user >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "用户 $user 存在"
else
echo "用户 $user 不存在"
fi
- 这个脚本会检查用户 "testuser" 是否存在,并输出相应的提示信息。
#-ne 不等于
#-eq 等于
下面是一个 Bash 脚本示例,通过输入用户名并判断该用户在系统中是否存在。脚本会使用 `id` 命令或检查 `/etc/passwd` 文件来验证用户是否存在。
```bash
#!/bin/bash
##########################################
####################
# File Name: check_user.sh
# Version: V1.0
# Author: oldboy lidao996
# Organization: www.oldboyedu.com
# Desc: 判断输入的用户名是否存在于系统中
##########################################
# 提示用户输入用户名
echo -n "请输入用户名: "
read username
# 判断输入是否为空
if [ -z "$username" ]; then
echo "错误:用户名不能为空!"
exit 1
fi
# 方法1:使用 id 命令检查用户是否存在
if id "$username" >/dev/null 2>&1; then
echo "用户 $username 存在于系统中。"
else
echo "用户 $username 不存在于系统中。"
fi
# 方法2(备用):检查 /etc/passwd 文件
# if grep -q "^$username:" /etc/passwd; then
# echo "用户 $username 存在于系统中。"
# else
# echo "用户 $username 不存在于系统中。"
# fi
```
---
### 脚本说明
1. **`read` 命令**:
- `read username` 用于接收用户输入的用户名。
- `echo -n` 使提示信息不换行,输入更友好。
2. **输入校验**:
- 使用 `[ -z "$username" ]` 检查输入是否为空,若为空则退出脚本。
3. **用户存在性判断**:
- **方法1**: 使用 `id "$username"` 检查用户是否存在。
- `>/dev/null 2>&1` 将输出和错误信息重定向到空设备,避免显示无关信息。
- 如果 `id` 返回成功(即用户存在),条件为真。
- **方法2** (注释掉的备用方法): 使用 `grep` 检查 `/etc/passwd` 文件中是否有该用户名。
- `^$username:` 确保匹配用户名的开头,`-q` 表示安静模式(不输出结果)。
4. **输出结果**:
- 根据判断结果,输出用户是否存在。
---
### 使用方法
1. 保存脚本为 `check_user.sh`。
2. 赋予执行权限:
```bash
chmod +x check_user.sh
```
3. 运行脚本:
```bash
./check_user.sh
```
### 示例输出
- 检查存在的用户(如 `root`):
```
请输入用户名: root
用户 root 存在于系统中。
```
- 检查不存在的用户:
```
请输入用户名: fakeuser
用户 fakeuser 不存在于系统中。
```
- 输入为空:
```
请输入用户名:
错误:用户名不能为空!
```
---
### 扩展功能(可选)
如果你需要更复杂的功能,可以告诉我,比如:
- 循环输入直到用户退出。
- 检查用户是否属于某个特定组。
- 显示用户的详细信息(如 UID、GID 等)。
四: 几个基础脚本分析
检查ip或域名是否可以访问脚本
下面是一个 Bash 脚本,用于检查指定的 IP 地址或域名是否可以访问。脚本将使用 `ping` 命令测试网络连通性,并提供简单的判断结果。
```bash
#!/bin/bash
##########################################
####################
# File Name: check_connectivity.sh
# Version: V1.0
# Desc: 检查指定的 IP 地址或域名是否可以访问
##########################################
# 提示用户输入 IP 或域名
echo -n "请输入 IP 地址或域名: "
read target
# 判断输入是否为空
if [ -z "$target" ]; then
echo "错误:输入不能为空!"
exit 1
fi
# 使用 ping 命令测试连通性(发送 4 个数据包)
echo "正在测试 $target 的连通性..."
if ping -c 4 "$target" >/dev/null 2>&1; then
echo "$target 可以访问。"
else
echo "$target 无法访问。"
fi
```
---
### 脚本说明
1. **`read` 命令**:
- 用于接收用户输入的 IP 地址或域名,存储在 `target` 变量中。
2. **输入校验**:
- 使用 `[ -z "$target" ]` 检查输入是否为空,若为空则退出脚本。
3. **`ping` 命令**:
- `-c 4`: 指定发送 4 个数据包。
- `>/dev/null 2>&1`: 将标准输出和错误输出重定向到空设备,避免显示详细的 ping 信息。
- 如果 `ping` 返回成功(即目标可达),条件为真。
4. **输出结果**:
- 根据 `ping` 的返回值,判断目标是否可访问。
---
### 使用方法
1. 保存脚本为 `check_connectivity.sh`。
2. 赋予执行权限:
```bash
chmod +x check_connectivity.sh
```
3. 运行脚本:
```bash
./check_connectivity.sh
```
### 示例输出
- 检查可访问的目标(如 `google.com`):
```
请输入 IP 地址或域名: google.com
正在测试 google.com 的连通性...
google.com 可以访问。
```
- 检查不可访问的目标(如无效域名):
```
请输入 IP 地址或域名: invalid.domain
正在测试 invalid.domain 的连通性...
invalid.domain 无法访问。
```
- 输入为空:
```
请输入 IP 地址或域名:
错误:输入不能为空!
```
---
### 扩展功能
如果需要更强大的功能,可以考虑以下改进:
1. **使用 `nc` 检查特定端口**:
如果想测试某个端口是否开放,可以用 `nc`(netcat)替代 `ping`:
```bash
echo -n "请输入 IP 地址或域名: "
read target
echo -n "请输入端口号: "
read port
if [ -z "$target" ] || [ -z "$port" ]; then
echo "错误:输入不能为空!"
exit 1
fi
if nc -z -w 5 "$target" "$port" >/dev/null 2>&1; then
echo "$target:$port 可以访问。"
else
echo "$target:$port 无法访问。"
fi
```
- `-z`: 扫描模式,不发送数据。
- `-w 5`: 设置超时为 5 秒。
2. **支持批量检查**:
可以从文件读取多个 IP/域名进行测试。
3. **更详细的输出**:
显示延迟时间、丢包率等(需要保留 `ping` 的输出并解析)。
---
### 注意事项
- **权限**: 普通用户可以运行 `ping`,但某些网络环境下可能被防火墙拦截。
- **依赖**: 脚本依赖 `ping` 命令,确保系统中已安装(通常默认存在)。
- **超时**: `ping -c 4` 默认等待时间较短,若网络较慢,可增加 `-c` 值或添加超时选项(如 `-W 5`)。
#大于9后,会表示为$1 + 0 第1个参数+0使用 ${}
下面是一个 Bash 脚本,用于创建一个简单的回收站功能,替代 `rm` 命令。被“删除”的文件不会直接被移除,而是移动到一个指定的回收站目录中,类似于操作系统的回收站机制。
```bash
#!/bin/bash
##########################################
####################
# File Name: safe_rm.sh
# Version: V1.0
# Author: oldboy lidao996
# Organization: www.oldboyedu.com
# Desc: 替代 rm 命令,将文件移动到回收站而不是直接删除
##########################################
# 定义回收站目录
TRASH_DIR="$HOME/.trash"
# 创建回收站目录(如果不存在)
[ ! -d "$TRASH_DIR" ] && mkdir -p "$TRASH_DIR"
# 检查是否提供了参数
if [ $# -eq 0 ]; then
echo "用法: $0 文件1 [文件2 ...]"
echo "将文件移动到回收站: $TRASH_DIR"
exit 1
fi
# 遍历所有输入的参数(文件或目录)
for file in "$@"; do
# 检查文件是否存在
if [ ! -e "$file" ]; then
echo "错误: '$file' 不存在!"
continue
fi
# 获取文件名和绝对路径
file_name=$(basename "$file")
file_path=$(realpath "$file")
# 为避免同名文件覆盖,添加时间戳
timestamp=$(date +%Y%m%d_%H%M%S)
trash_file="$TRASH_DIR/${file_name}_$timestamp"
# 移动文件到回收站
if mv "$file_path" "$trash_file"; then
echo "已移动 '$file' 到回收站: $trash_file"
else
echo "错误: 无法移动 '$file' 到回收站!"
fi
done
```
---
### 脚本说明
1. **回收站目录**:
- 定义在用户家目录下的 `.trash` 文件夹(`$HOME/.trash`)。
- 使用 `[ ! -d "$TRASH_DIR" ] && mkdir -p "$TRASH_DIR"` 确保目录存在。
2. **参数检查**:
- 使用 `$#` 检查是否提供了文件参数,若无参数则显示用法并退出。
3. **文件处理**:
- 通过 `for` 循环遍历所有输入的文件(`$@`)。
- 使用 `[ ! -e "$file" ]` 检查文件是否存在。
- `basename` 获取文件名,`realpath` 获取文件绝对路径。
- 添加时间戳(如 `20250225_143022`)避免同名文件覆盖。
4. **`mv` 命令**:
- 将文件移动到回收站目录,而不是删除。
- 提供成功或失败的反馈。
---
### 使用方法
1. 保存脚本为 `safe_rm.sh`。
2. 赋予执行权限:
```bash
chmod +x safe_rm.sh
```
3. 运行脚本(测试删除文件):
```bash
./safe_rm.sh file1.txt file2.txt
```
### 示例输出
```
$ ./safe_rm.sh test.txt
已移动 'test.txt' 到回收站: /home/user/.trash/test.txt_20250225_143022
$ ./safe_rm.sh nonexistent.txt
错误: 'nonexistent.txt' 不存在!
```
---
### 如何替代 `rm` 命令
要让 `safe_rm.sh` 替代系统默认的 `rm` 命令,可以通过以下方式设置别名:
1. 编辑 `~/.bashrc` 或 `~/.bash_profile`:
```bash
nano ~/.bashrc
```
2. 添加别名:
```bash
alias rm='/path/to/safe_rm.sh'
```
3. 保存并刷新配置:
```bash
source ~/.bashrc
```
4. 之后,输入 `rm file` 将调用 `safe_rm.sh`,而非直接删除文件。
**注意**:如果需要使用原生的 `rm` 命令,可以用完整路径 `/bin/rm` 或加反斜杠 `\rm`。
---
### 扩展功能(可选)
1. **恢复文件**:
添加选项(如 `-r`)从回收站恢复文件:
```bash
if [ "$1" = "-r" ]; then
shift
mv "$TRASH_DIR/$1" ./
echo "已恢复 '$1' 到当前目录。"
exit 0
fi
```
2. **清空回收站**:
添加选项(如 `--empty`)清空回收站:
```bash
if [ "$1" = "--empty" ]; then
rm -rf "$TRASH_DIR"/*
echo "回收站已清空。"
exit 0
fi
```
3. **日志记录**:
记录每次删除的文件和时间到日志文件。
最后
alias rm='sh /server/scripts/devopsshell/06.recyle_rm.sh'
799

被折叠的 条评论
为什么被折叠?



