我一直在尝试找出一个Bash脚本文件,该文件通过浏览大量文档并在线搜索来启动一些Docker容器(我对Bash还是很陌生)。但是,我根本无法弄清楚以下行的作用:
which systemctl 2>&1 >/dev/null && systemctl stop firewalld && systemctl restart docker
我了解2>&1> / dev / null部分。
我也了解“哪个”是一种实用工具,它基本上通过引用PATH信息将可执行文件的完整路径打印到STDOUT(如果我错了,请纠正我),我认为它不是最受推荐的实用工具,因为它不是在不同的UNIX-y系统上通用。
但是,我根本不理解该行。
我尝试通过输入which node
,which docker
之类的东西来玩游戏,其行为符合预期,但我完全不了解上一行的情况。
作为参考,整个代码及其输出如下:
PROVISION_PORT=3000
HLF_WORKSPACE=~/HLF_workspace
usage() {
echo "Usage: $0 [-p provision_port] [-d HLF_workspace_path]" # $0: 0th arg -> ./setupProvCont
}
if [ $# -eq 0 ]
then
echo "No input parameter, will use default settings"
fi
while getopts "p:d:h" arg #get options
do
case $arg in
h)
usage
exit #exit 0 -> normal exit
;;
p)
PROVISION_PORT=$OPTARG #optional arguments
;;
d)
HLF_WORKSPACE=$OPTARG
;;
?)
usage
exit 1 #exit 1 -> error exit, unknown flag used
;;
esac
done
which systemctl 2>&1 >/dev/null && systemctl stop firewalld && systemctl restart docker
echo "Starting Provision..."
echo "docker run -it -u `id -u $USER` --network=host -e "PROVISION_PORT=$PROVISION_PORT" -e \"BCS_DOCKER_WORKSPACE=$HLF_WORKSPACE\" -e \"VM_HOSTNAME=`hostname`\" -v /var/run:/var/run -v $HLF_WORKSPACE:$HLF_WORKSPACE -d oracle/HLF-provision"
docker run -it -u `id -u $USER` --network=host -e "PROVISION_PORT=$PROVISION_PORT" -e "BCS_DOCKER_WORKSPACE=$HLF_WORKSPACE" -e "VM_HOSTNAME=`hostname`" -v /var/run:/var/run -v $HLF_WORKSPACE:$HLF_WORKSPACE -d oracle/HLF-provision
输出:
[hlf@hlfdemo hlf_fabric]$ ./setupProvisionContainer.sh
No input parameter, will use default settings
Starting Provision...
docker run -it -u 1000 --network=host -e PROVISION_PORT=3000 -e "BCS_DOCKER_WORKSPACE=/home/hlf/HLF_workspace" -e "VM_HOSTNAME=hlfdemo.internal" -v /var/run:/var/run -v /home/hlf/HLF_workspace:/home/hlf/HLF_workspace -d hlf/HLF-provision
b7f3073cc218b70525341c1770aaef17fc41c8e76f858807e7fd6e995594c60d
[hlf@hlfdemo hlf_fabric]$
答案 0 :(得分:0)
命令
which systemctl 2>&1 >/dev/null && systemctl stop firewalld && systemctl restart docker
是由布尔运算符&&
分隔的三个命令的AND列表。
它们从左到右执行,并且AND运算符(&&
)检查其左命令的退出代码并仅在该退出代码为0
时调用右命令(这表示“成功“)。
从根本上讲,这意味着命令将一一执行,直到其中一个失败为止。
在本示例中,通常使用 which
来检查程序是否可用,以确保可以执行其后的命令。如果程序不可用,则不执行它们(which
如果找不到程序,则以退出代码1
结束)。
which
的输出和错误被重定向到/dev/null
(它们基本上被丢弃了),因为这里我们不需要知道systemctl
的位置,只有在它存在的情况下(并且会在列表中的下一个命令直接调用时可以找到。
您始终可以通过检查特殊shell变量$?
的内容来检查上一条命令的退出代码:
$ which ls
/bin/ls
$ echo $?
0
$ which some-program-that-does-not-exist
$ echo $?
1
更新
重定向分别应用于每个简单命令,并且不会影响其他命令。
此命令行中包含三个简单命令:
which systemctl 2>&1 >/dev/null
systemctl stop firewalld
systemctl restart docker
仅第一个重定向了stdout
和stderr
,其他两个不受影响,它们将其输出(和错误)发送到标准输出和错误流(默认情况下已连接)到终端)。
从左到右处理重定向。
首先,2>&1
复制文件描述符1
(stdout
),并将副本存储在文件描述符2
(stderr
)下。用简单的英语来说,这意味着2>&1
之后,stderr
会将其内容发送到stdout
相同的流中。
然后,>/dev/null
更改stdout
(仅stdout
)以指向特殊文件/dev/null
。
/dev/null
是一个不占用空间的特殊文件,写入该文件的所有内容都将被丢弃。将stdout
和/或stderr
重定向到它是丢弃输出和/或命令错误的标准Unix方法。
请注意,在2>&1 >/dev/null
之后,stdout
指向/dev/null
,而stderr
指向stdout
的先前值,而不是 /dev/null
,但控制台(终端窗口);这也是stderr
的先前值。
换句话说,这会错误地使stderr
将其内容发送到终端,并且仅重定向stdout
。
正确的方法是先将stdout
重定向,然后 将重复的stdout
重定向到stderr
:
which systemctl >/dev/null 2>&1
或者您可以使用&>
重定向运算符将stdout
和stderr
都重定向到同一文件:
which systemctl &>/dev/null