我试图理解下面这段 shell 脚本的作用。我知道不带任何参数的 exec 会重定向当前 shell 的输出,但我无法理解以下命令的作用:
exec 1>/var/opt/log/my_logs/MYPROG_`date '+%Y%m%d_%H%M%S'`.log 2>&1
答案1
实际上有 4 个重要的信息正在发生:
内置
exec
用于将命令行会话的所有输出重定向到文件告诉
1><FILENAME>
shell 重定向stdout
标准流,即命令的正常非错误输出将转到<FILENAME>
。>
如果<FILENAME>
不存在,将创建;如果<FILENAME>
已存在,将截断。重定向文件名是通过在
date '+%Y%m%d_%H%M%S'
命令中添加反引号创建的。反引号是命令替换 和 在功能上等同于$(date '+%Y%m%d_%H%M%S')
形式,如今$(...)
更倾向于使用 ,因为它更易于阅读,并且这种形式可以轻松嵌套(即具有多个级别)。因此,date
使用指定格式 的输出'+%Y%m%d_%H%M%S'
将创建带有时间戳的文件名。如果您的命令在 2018 年 7 月 4 日 4:20:20 运行,则输出将为/var/opt/log/my_logs/MYPROG_20180704_042020.log
。2>&1
重定向stderr
流到该文件,它是一种标准的、符合 POSIX 的bash
格式(这意味着除了理解它之外,Bourne 类 shell 也是如此)。这是功能等同于&>
bash 特定的语法。shell 中指定的重定向的顺序很重要,这就是为什么它出现在1>
重定向之后。
总之,此命令本身不应有任何输出。它应该只将所有连续命令的两个输出流重新连接以进入您指定的文件。
有趣的是,使用此命令我bash 4.4
会将所有内容输出到文件中,其中包括提示符和我输入的任何内容(因此在这里我必须盲目输入echo hello world
然后按 Ctrl+D 退出):
$ bash --posix
bash-4.4$ exec 1>./mylog_`date '+%Y%m%d_%H%M%S'`.log 2>&1
$ cat ./mylog_20180424_010800.log
bash-4.4$ echo hello world
hello world
bash-4.4$ exit
逐一进行上述操作后,我们发现bash
输出提示可以stderr
流式传输,而且令人惊讶的是,输出的内容与我输入的任何内容一致:
bash-4.4$ exec 1> ./mylog.txt
bash-4.4$ echo Hello World
bash-4.4$ cat ./mylog.txt
cat: ./mylog.txt: input file is output file
bash-4.4$ exec 2>&1
如果ksh
发生同样的事情,但我可以看到正在输入的内容,只有提示进入文件,即 stdin 没有被重定向:
bash-4.4$ ksh
$ exec 1>./mylog 2>&1
echo hello askubuntu
bash-4.4$ cat ./mylog
$ hello askubuntu
$
bash-4.4$
所以在这里我们可以看到,shell 可以选择将提示输出PS1
到标准流之一,以便将其包含在文件中。