Shell中, 退出整个脚本

常规做法

cat >test.sh<<EOF''
#!/bin/bash

exit_script(){
	exit 1
}

echo "before exit"
exit_script
echo "after exit"
EOF

chmod a+x test.sh
./test.sh
echo $?

# 输出
before exit
1

可以看到直接使用exit可以退出脚本,并且可以将错误码作为参数传递。下面我们将脚本做一点点改动。

存在的问题

cat >test.sh<<EOF''
#!/bin/bash

exit_script(){
	exit 1
}

echo "before exit"
:|exit_script
echo "after exit"
EOF

chmod a+x test.sh
./test.sh
echo $?

# 输出
before exit
after exit
0

管道(|)中执行exit_script函数,不会退出整个脚本!原因在于,exit只能退出它所在的Shell,而放在管道中执行的命令/函数都是在独立的Shell(Sub-Shell)中执行的,所以上面脚本的进程树是这个样子的:

 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
17510 26959 26959 26959 pts/0    14049 Ss       0   0:00  \_ -bash
26959 13843 13843 26959 pts/0    14049 S        0   0:00  |   \_ /bin/bash ./test.sh
13843 13844 13843 26959 pts/0    14049 S        0   0:00  |   |   \_ :
13843 13845 13843 26959 pts/0    14049 S        0   0:00  |   |   \_ /bin/bash ./test.sh
13845 13846 13843 26959 pts/0    14049 S        0   0:00  |   |       \_ exit 1

自上往下,各个PID的含义如下表:

PID 说明
26959 ./test.sh所在的Shell
13843 管道中:新开的Shell
13844 :命令
13845 管道中exit_shell新开的Shell
13846 exit命令

使用trapkill退出整个脚本

cat >test.sh<<EOF''
#!/bin/bash

export TOP_PID=$$
trap 'exit 1' TERM

exit_script(){
	kill -s TERM $TOP_PID
}

echo "before exit"
:|exit_script
echo "after exit"
EOF

chmod a+x test.sh
./test.sh
echo $?

# 输出
before exit
1

这里首先在脚本的主进程中捕获(trap) TERM信号: 当主进程接收到TERM信号后,会执行exit 1;再在Sub-Shell中向脚本主进程发送TERM信号,这样就可以让整个脚本退出了!

posted @ 2017-03-17 15:27  广岛之恋  阅读(41998)  评论(0编辑  收藏  举报