在UNIX shell脚本中:$!扩展成什么?

4
在shell或shell脚本中,$!是什么意思?我正在尝试理解一个脚本,其中有类似以下内容的东西。
local@usr> a=1
local@usr> echo $a
1
local@usr> echo $!a
a

它将变量打印回来。这就是全部吗?我们还有哪些$x选项?我知道的只有$$、$*、$?。如果有人能给我指点一个好的来源,那就太有帮助了。顺便说一下,这是在Sun OS 5.8、KSH中。


1
我觉得很惊奇的是,被接受的答案建立在对Bash手册的引用上,而你指定的是ksh(Sun OS 5.8)。 - user2350426
当时,我没有看出BASH和KSH之间的区别。 - Guru
5个回答

6

各种$…变量在Bash手册中有详细描述。根据手册,$!会展开为后台启动的最后一个进程的PID。参见:

$ echo "Foo"
Foo
$ echo $!

$ true&
[1] 67064
$ echo $!
67064
[1]+  Done                    true

ksh 中似乎也是这样做的。

那是什么意思?我尝试了但是我不明白它是什么? usr> echo $! 17893 usr> false usr> echo $! 17893 - Guru
1
大师,试一下这个:sleep 120 & ; echo $1 ; ps -ef | grep $! - paxdiablo
这是上一个后台作业的 PID - 直到您运行另一个后台作业它才会改变。 - paxdiablo
@paxdiablo。太好了。现在,我明白了。 - Guru

2

以下是我系统上 ksh 命令的说明:

  ${!vname}
      展开为变量 vname 所引用的变量名称。当 vname 是一个名称引用时,这将不是 vname。

一个例子可以吗?"Expands"让我感到困惑。 :( - Guru
运行 man ksh 命令会显示太多内容无法复制到答案中。 - Greg Hewgill
1
这种形式被称为间接引用。a=1; b=a; echo ${!b} 的结果是打印出 "1"。 - Dennis Williamson
Shell扩展${!var}不是所要求的,应该是$! - user2350426

1
对于你所询问的ksh shell,请参见ksh手册,并阅读以下内容:

参数替换
参数是标识符、一个或多个数字,或以下任意字符之一: *、@、#、?、-、$ 和 !。

很明显,这些被接受的选项有$*、$@、$#、$?、$-、$$ 和 $!。
未来可能会包括更多选项。

针对参数 $!,根据手册:

"!" 表示最后一个后台命令的进程号。

如果你启动了一个后台进程,比如 sleep 60 &,那么该进程将会有一个进程号,参数 $! 将会打印出它的进程号。

$ sleep 60 &
[1] 12329
$ echo "$!"
12329

如果没有后台进程在执行(例如当shell启动时),扩展结果为空。它具有空值。
$ ksh -c 'echo $!'

如果有后台进程,它将扩展到该进程的PID:

$  ksh -c 'sleep 30 & echo $!'
42586

这就是为什么echo $!a会扩展为a。因为没有PID可报告:
$  ksh -c 'echo $!a'
a

其他Shell可能有不同(通常非常相似)的扩展列表(一个参数只有一个$和下一个字符)。例如,bash将*@#?-$!0_识别为“特殊参数”。请搜索Bash手册中的“3.4.2特殊参数”标题。

特殊参数
Shell会特别处理几个参数。


0

它提供了上一个后台作业或后台函数的进程ID,请查看下面的链接

http://www.well.ox.ac.uk/~johnb/comp/unix/ksh.html#specvar

0

在Unix中,!是一个引用运算符,尽管它不被称为这个名字。

它总是指向一个母进程。在vi中尝试输入:!,它会带你到命令提示符,你可以像平常一样执行命令,直到退出命令。

在SQLPLUS中,!也可以从命令提示符执行命令。在sqlplus中尝试这个:

SQL> !ls --- 这将给出当前目录中的文件列表。

$! - 显然给出当前/最新进程的进程ID。


在完全不相关的语言或环境中提及300万种其他用途的情况下,将-1用于命名是没有意义的。"$!"在shell中只有一个意思(如果之前没有学习过,这一点显然并不明显)。 - Jens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接