Linux shell exec command

shell中exec命令

语法格式

exec [-cl] [-a name] [command [arguments]]

选项说明

-c  #在空环境中执行指定的命令
-l  #在传递给command的第零个arg的开头放置一个破折号
-a  #Shell将name作为第零个参数传递给command

应用举例

  • 输出指定信息
1
2
3
4
> echo "hello world"
hello world
> exec -c echo hello world
hello world
  • 其它使用总结
1
2
3
4
5
6
7
8
9
exec ls     #在 shell 中执行 ls,ls 结束后不返回原来的 shell 中了
exec        #file 中的内容作为标准输入(替代 STDIN)
exec >file  #将标准输出写入file(替代STDOUT)
exec 3      #将 file 读入到文件描述符 3 中(此时,创建了文件描述符 3)
sort <&3    #将文件描述符3作为临时输入,用于 sort 排序
exec 4>file #将写入文件描述符 4 中的内容写入 file 中(此时,创建了文件描述符 4)
ls >&4      #ls将不会有显示,直接写入文件描述符 4 中了,即上面的 file 中
exec 5<&4   #创建文件描述符 4 的拷贝文件描述符 5
exec 3<&-   #关闭文件描述符 3
  • exec执行命令时,不会启用新的shell进程。

  • exec是用被执行的命令行替换掉当前的shell进程, 进程的PID保持不变,且exec命令后的其他命令将不再执行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
> cat test.sh
#/bin/bash

echo "Hello World"
exec echo "Hello bash"
echo "Hello Done"

> sh ./test.sh
Hello World
Hello bash

程序在exec执行后结束退出

循环执行脚本本身

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
> cat test.sh
#/bin/bash

echo `date +"%Y-%m-%d %H:%M:%S"` $$
sleep 2s
exec sh "$0"

> sh ./test.sh
2021-08-30 22:50:51 73016
2021-08-30 22:50:53 73016
2021-08-30 22:50:55 73016

shell中的${ }

  • 可以用${}分别替换得到不同的值:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
file=/dir1/dir2/dir3/my.file.txt

${file#*/}: 删掉第一个/ 及其左边的字符串:dir1/dir2/dir3/my.file.txt
${file##*/}:删掉最后一个/  及其左边的字符串:my.file.txt
${file#*.}: 删掉第一个.  及其左边的字符串:file.txt
${file##*.}:删掉最后一个.  及其左边的字符串:txt
${file%/*}: 删掉最后一个 /  及其右边的字符串:/dir1/dir2/dir3
${file%%/*}:删掉第一个/  及其右边的字符串:(空值)
${file%.*}: 删掉最后一个 .  及其右边的字符串:/dir1/dir2/dir3/my.file
${file%%.*}:删掉第一个 .   及其右边的字符串:/dir1/dir2/dir3/my

单一符号是最小匹配;两个符号是最大匹配
# 是去掉左边(键盘上#在 $ 的左边)
% 是去掉右边(键盘上% 在$ 的右边)

${file:0:5}:提取最左边的5 个字节:/dir1
${file:5:5}:提取第5 个字节右边的连续5个字节:/dir2
  • 替换变量值里的字符串:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
${file/dir/path}:将第一个dir 替换为path:/path1/dir2/dir3/my.file.txt
${file//dir/path}:将全部dir 替换为path:/path1/path2/path3/my.file.txt

利用${  } 可针对不同的变数状态赋值(沒设定、空值、非空值): 
${file-my.file.txt} : 假如$file 沒有设定,則使用my.file.txt 作传回值。(空值及非空值時不作处理) 
${file:-my.file.txt} :假如$file 沒有設定或為空值,則使用my.file.txt 作傳回值。(非空值時不作处理)
${file+my.file.txt} : 假如$file 設為空值或非空值,均使用my.file.txt 作傳回值。(沒設定時不作处理)
${file:+my.file.txt} :若$file 為非空值,則使用my.file.txt 作傳回值。(沒設定及空值時不作处理)
${file=my.file.txt} : 若$file 沒設定,則使用my.file.txt 作傳回值,同時將$file 賦值為my.file.txt 。(空值及非空值時不作处理)
${file:=my.file.txt} :若$file 沒設定或為空值,則使用my.file.txt 作傳回值,同時將$file 賦值為my.file.txt 。(非空值時不作处理)
${file?my.file.txt} : 若$file 沒設定,則將my.file.txt 輸出至STDERR。(空值及非空值時不作处理)

${file:?my.file.txt} :若$file 没设定或为空值,则将my.file.txt 输出至STDERR。(非空值時不作处理)

${#var} 可计算出变量值的长度:

${#file} 可得到27 ,因为/dir1/dir2/dir3/my.file.txt 是27个字节

shell 中的$0 $1 $* $@ $# $$ $?

  • $0: 脚本本身文件名称

  • $1 ~ $n:参数1 ~ 参数n

  • $#: 参数个数

  • $$: 脚本运行时的PID

  • $?: 获取函数的返回值或者上一个命令的退出状态 。如果成功就是0,失败为1。常用if [ $? -eq 0 ] 来判断一个命令有没有执行成功。

  • $*: 所有参数列表

  • $@: 所有参数列表

$@与$*的区别:

  • $@与$*都可以使用一个变量来来表示所有的参数内容,但这两个变量之间有一些不同之处。

  • $@:将输入的所有参数作为一个列表对象

  • $*:将输入的所有参数作为一个变量

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
> cat test.sh
#/bin/bash

echo $*
echo $@

n=1
for i in "$*"
do
    echo "$n : " $i
    let n+=1
done

n=1
for i in "$@"
do
    echo "$n : " $i
    let n+=1
done

n=1
for i in $*
do
    echo "$n : " $i
    let n+=1
done

> sh ./test.sh 1 2 3 4
1 2 3 4
1 2 3 4
1 :  1 2 3 4
1 :  1
2 :  2
3 :  3
4 :  4
1 :  1
2 :  2
3 :  3
4 :  4

在上面的例子中,使用$@与$*,都是用双引号引起来,但当$*不使用双引号时,结果与$@的结果相同。

当命令行为test.sh 1 2 3 4

  • “$*“表示"1 2 3 4”

  • “$@“表示"1” “2” “3” “4”

参考