子shell的$$

下面是一段代码,我偶然发现有点问题。

[plain]  view plain copy print ?
  1. #!/bin/bash  
  2.   
  3. TestID()  
  4. {  
  5.         echo "in function : $$"  
  6. }  
  7.   
  8. TestID &  
  9. echo "\$! : $! "  
  10.   
  11. echo "\$\$ : $$ "  
  12. sleep 1  

[firefox@fire ShellPractice]$ ./stopped.sh
$! : 15021
$$ : 15020
in function : 15020

疑问就是在这里,$!代表是最后一个后台程序的ID$$当前进程ID,而&出来的应该是一个子shell但是它的ID(在子shell里这时候是$$打印出来的)和父shell是“一样”的。我去论坛上问了下,然后查了些资料。下面是一些简单的介绍:


shell什么情况下会产生子进程

1:&,提交后台作业

If a command is terminated by the control operator `&’, the shell executes the command asynchronously in a subshell.

2:管道

Each command in a pipeline is executed in its own subshell

3:括号命令列表

()操作符

Placing a list of commands between parentheses causes a subshell environment to be created

4:执行外部脚本、程序:

When Bash finds such a file while searching the `$PATH’ for a command, it spawns a subshell to execute it.  In other words, executing  filename ARGUMENTS is equivalent to executing bash filename ARGUMENTS

再看看 man bash 里面对于$的解释

“$”  Expands to the process ID of the shell. In a () subshell, it  expands to the process ID of the current shellnot the sub‐shell.

那么这里的current shell怎么解释呢?字面意思是“当前的shell”。这里有有一篇博客讲子shell,我觉得讲的很好 http://blog.youkuaiyun.com/sosodream/article/details/5683515 。用 ./xxx.sh 执行脚本的时候也会生成子shell,原来的shell会有一个 ID,这里假设叫ID1,然后进入脚本,这时脚本里的$$就是current shell的ID(由ID1生出的子shell的ID)之后再生出其余的子shell的$$都是current shell的ID,也就是由ID1生出来的ID,注意:子shell的ID可不是$$。子shell有它自己的ID。至于怎么获取,一般都用$!来获取。

再来看看下面的脚本

[plain]  view plain copy print ?
  1. #!/bin/bash  
  2.   
  3. echo "\$\$ outside of subshell = $$"  
  4. echo "\$BASH_SUBSHELL outside of subshell = $BASH_SUBSHELL"  
  5. echo "\$BASHPID outside of subshell = $BASHPID"  
  6. echo "-------------------"  
  7. (  
  8.         echo "\$\$ inside of subshell = $$"  
  9.         echo "\$BASH_SUBSHELL inside of subshell = $BASH_SUBSHELL"  
  10.         echo "\$BASHPID inside of subshell = $BASHPID"  
  11. )  
  12. echo "-------------------"  

$BASHPID就是指当前shell。

现在再来看看 man bash 中“$”的解释

[root@fire ShellPractice]# echo $$
2618

如果你在子shell里面执行这条命令,其实是$$先替换为2618,然后再进行echo,$$一直都指的的是current shell。

<think> 我们正在讨论Shell脚本中的特殊变量`$$`。根据引用内容,`$$`表示当前Shell脚本运行的进程ID(PID)。这是一个只读变量,用于获取当前脚本执行时的进程ID。 ### 核心知识点 1. **基本含义**:`$$` 表示当前Shell脚本的进程ID(PID),每次运行脚本时都会生成一个唯一的PID。 2. **使用场景**: - 创建临时文件或目录时,为避免文件名冲突,常用`$$`生成唯一后缀。 - 调试脚本时,可通过PID跟踪脚本的执行情况。 - 在后台运行脚本时,可通过`$$`获取进程ID以便后续操作(如终止进程)。 3. **特性**:`$$`的值在脚本启动时确定,在整个脚本执行过程中保持不变。 ### 示例演示 创建一个脚本`test_pid.sh`: ```bash #!/bin/bash echo "当前脚本的进程ID (PID) 是: $$" # 创建临时文件 TMP_FILE="/tmp/tempfile_$$.txt" echo "这是一个临时文件" > $TMP_FILE echo "临时文件已创建: $TMP_FILE" # 显示临时文件内容 cat $TMP_FILE # 清理(可选) # rm -f $TMP_FILE ``` 运行脚本: ```bash $ chmod +x test_pid.sh $ ./test_pid.sh ``` 输出示例: ``` 当前脚本的进程ID (PID) 是: 12345 临时文件已创建: /tmp/tempfile_12345.txt 这是一个临时文件 ``` ### 重要注意事项 - **Shell中的`$$`**:在Shell(如`( )`或`bash -c`)中,`$$`会继承父Shell的PID,而非Shell自身的PID。如需获取Shell的PID,可使用`$BASHPID`(Bash特有): ```bash echo "父Shell PID: $$" ( echo "Shell继承的PID: $$"; echo "Shell实际PID: $BASHPID" ) ``` ### 与其他特殊变量对比 | 变量 | 含义 | 示例用法 | |------|-------------------------------|------------------------------| | `$$` | 当前脚本的进程ID | `echo "PID: $$"` | | `$!` | 最后一个后台命令的进程ID | `nohup command & echo $!` | | `$?` | 上一条命令的退出状态码 | `if [ $? -eq 0 ]; then ...` | | `$#` | 脚本参数的个数 | `if [ $# -lt 2 ]; then ...` | ### 常见问题解答 **Q1: 如何确保临时文件的唯一性?** > 仅用`$$`可能不足(同一脚本多次运行PID可能重复),可结合`date`或`mktemp`命令: > ```bash > TMP_FILE="/tmp/$(date +%s)_$$.txt" # 时间戳+PID > # 或使用系统工具 > TMP_FILE=$(mktemp /tmp/tempfile_XXXXXX.txt) > ``` **Q2: 如何终止当前脚本进程?** > 使用`kill -9 $$`可在脚本内部终止自身(谨慎使用): > ```bash > echo "即将终止脚本..." > kill -9 $$ > ``` **Q3: Shell中如何获取真实PID?** > 在Bash中,优先使用`$BASHPID`获取Shell的真实PID: > ```bash > ( sleep 10 & echo "Shell后台进程PID: $BASHPID" ) > ``` ### 相关应用场景 1. **进程管理**:编写守护进程脚本时,通过`$$`记录PID以便后续控制。 2. **日志跟踪**:在日志中记录PID,便于多进程环境下的问题排查。 3. **资源隔离**:使用PID命名管道(FIFO)、共享内存等资源。 §§ 相关问题 §§ 1. Shell中`$!`和`$$`有什么区别? 2. 如何获取Shell的真实进程ID? 3. 为什么临时文件命名推荐使用`mktemp`而不是`$$`? </think> ### Shell 中 `$$` 的含义和用法详解 在 Shell 脚本中,**`$$` 表示当前 Shell 进程的进程 ID (PID)**。这是一个特殊的只读变量,用于获取当前正在运行的脚本或命令的进程标识符。以下是详细解析: #### 一、核心特性 | **特性** | **说明** | |-----------------|--------------------------------------------------------------------------| | **只读变量** | 值由系统自动分配,脚本无法修改 | | **实时获取** | 每次执行脚本时都会生成新的 PID | | **全局唯一性** | 同一时刻系统中每个进程的 PID 唯一 | | **会话绑定** | 进程会继承父进程的 PID(需区分 `$$` 和 `$BASHPID`)[^5] | #### 二、典型用法示例 ##### 1. 获取当前脚本 PID ```bash #!/bin/bash echo "当前脚本进程 ID: $$" # 输出如:当前脚本进程 ID: 12345 ``` ##### 2. 创建唯一临时文件 ```bash temp_file="/tmp/data_$$.tmp" # 生成如 /tmp/data_12345.tmp echo "内容" > "$temp_file" ``` ##### 3. 进程管理 ```bash #!/bin/bash # 记录自身 PID echo $$ > /var/run/myscript.pid # 后续可通过该 PID 管理进程 # kill -9 $(cat /var/run/myscript.pid) ``` ##### 4. 调试多进程脚本 ```bash #!/bin/bash echo "父进程 PID: $$" ( echo "进程 PID: $$ (继承父进程)" # 注意:Shell$$ 不变 echo "真实进程 PID: $BASHPID" # 需用 $BASHPID 获取实际 PID ) ``` #### 三、技术细节解析 1. **PID 分配机制** - 由内核在进程创建时分配 - 取值范围:`1 ~ 32768`(可通过 `sysctl kernel.pid_max` 查看上限) - 回收机制:进程结束后 PID 可重用 2. **父进程差异** ```bash # 父进程脚本 echo "父进程 PID: $$" bash -c 'echo "进程 PID: $$"' # 进程继承 $$ ``` 3. **与相关变量对比** | **变量** | **含义** | **示例** | |----------|---------------------------|----------------| | `$$` | 当前 Shell 的 PID | `12345` | | `$!` | 最后后台进程的 PID | `12346` | | `$BASHPID` | 当前 Bash 进程的真实 PID | `12347` (进程) | | `$PPID` | 父进程 PID | `12344` | #### 四、实际应用场景 1. **进程互斥锁** ```bash LOCKFILE="/tmp/myapp.lock" if [ -e $LOCKFILE ]; then echo "另一个实例正在运行(PID: $(cat $LOCKFILE))" exit 1 fi echo $$ > $LOCKFILE ``` 2. **日志追踪** ```bash log() { echo "[$$ $(date '+%F %T')] $@" >> /var/log/app.log } log "服务启动" ``` 3. **临时资源管理** ```bash WORK_DIR=$(mktemp -d /tmp/workdir_$$_XXX) # 创建唯一目录 trap "rm -rf $WORK_DIR" EXIT # 退出时自动清理 ``` #### 五、注意事项 1. **进程陷阱** ```bash # ❌ 错误:Shell继承相同 $$ ( echo "Subshell PID: $$" ) # ✅ 正确:使用 $BASHPID ( echo "真实 PID: $BASHPID" ) ``` 2. **PID 重用风险** - 长时间运行的脚本不应依赖 PID 作为唯一标识 - 建议组合使用时间戳:`id_$(date +%s)_$$` 3. **系统限制** - PID 最大值:`/proc/sys/kernel/pid_max` - 查看进程信息:`ps -p $$ -o pid,ppid,cmd` --- ### 相关问题 1. 如何在 Shell 脚本中获取进程的真实 PID? 2. `$$` 和 `$BASHPID` 在什么场景下会显示不同的值? 3. 如何防止 Shell 脚本被重复运行(实现单例模式)? 4. 除了 `$$`,还有哪些特殊变量可以用于进程管理?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值