在脚本中,我有一长串打印到标准输出的命令。我想隐藏所有输出。因此,我没有重定向每个命令,而是将
exec >/dev/null
一开始。
我必须使用哪些选项来“暂时忽略”一般重定向并echo
在实际打印到标准输出之间进行一次调用?
答案1
任何echo
都会打印到标准输出。只是您的标准输出现在指向/dev/null
.要点是,原始的标准输出一点也不特殊,或者比重定向后的标准输出更“真实”。
如果您想保留 stdout 最初指向的位置的副本,您可以将文件描述符复制到另一个数字并向那里发送您想要保留的任何输出:
exec 3>&1 # duplicate original stdout to fd 3
exec 1>/dev/null # send stdout to /dev/null
printf "what\n" # this goes to stdout = /dev/null
printf "hello " >&3 # this goes to fd 3 = original stdout
# optionally:
exec 1>&3 # put the original stdout back
exec 3>&- # close fd 3
printf "there\n" # to current stdout = original stdout again
或者在 Bash/ksh93/zsh 中使用动态分配的 fd(我希望我做对了):
exec {orig}>&1 # duplicate original stdout to some fd,
# store number in $orig
exec 1>/dev/null # send stdout to /dev/null
printf "what\n" # this goes to stdout = /dev/null
printf "hello " >&"$orig" # this goes to fd in $orig = original stdout
# optionally:
exec 1>&"$orig" # put the original stdout back
exec {orig}>&- # close fd in $orig
printf "there\n" # to current stdout = original stdout again
在这两种情况下,ksh93
都会使用 close-on-exec 标志标记 fd(3 或$orig
),bash / zsh 不会,尽管使用 bash 5.2 或更高版本,您可以shopt -s varredir_close
将 close-on-exec 标志添加到使用语法创建的 fds exec {var}>...
。
当该标志未设置时,这意味着 fd 3 将泄露到其他命令。例如,如果原始标准输出要发送到管道,并且您运行启动后台进程的命令,最终可能会导致该管道保持打开状态,那么这在实践中可能会出现问题。为这些人跑步cmd 3>&-
可以解决这个问题。
答案2
如果你想让echo
输出专门去到脚本启动的终端,你可以使用:
echo "some message" > /dev/tty
/dev/tty
有点“神奇”:无论哪个进程使用它,它总是会连接到与该进程关联的终端。
当然,如果您以这样的方式运行脚本不与任何终端关联(例如,从 crontab 中,或者在ssh somehost script.sh
不指定-t
选项的情况下ssh
),这将导致错误。
$ ssh hostname "echo foo > /dev/tty"
Enter passphrase for key...:
bash: line 1: /dev/tty: No such device or address
$ ssh -t hostname "echo foo > /dev/tty"
Enter passphrase for key...:
foo
Connection to hostname closed.
答案3
如果你有一个简单的命令列表,echo
中间有一个,你可以这样做
{ 命令1 命令2 命令3 命令4 } > /dev/null echo 'High Five' # 这将转到脚本的标准输出。 { 命令6 命令7 命令8 命令9 } > /dev/null
echo
如果位于复合命令(例如if
-then
或循环)内,则此方法不起作用。