BASH Shell将stderr重定向到stdout(将stderr重定向到File)
如何在bash下将stderr重定向到stdout?
使用bash时如何将stderr重定向到文件?
此页面说明了bash I/O重定向,可用于在shell提示符下或者shell脚本中将stderr和stdout重定向到文件。
stdin
从键盘或者程序获取输入。换句话说,数据进入程序。stdout
在屏幕或者文件上写信息。stderr
在屏幕或者文件上显示错误消息
Bash和其他现代Linux/Unix Shell提供了I/O重定向功能。
每个进程打开三个默认的标准文件(标准流):
了解I/O流编号
带有数字的Unix/Linux标准I/O流:
句柄 | 名称 | 描述 |
0 | stdin | 标准输入 |
1 | stdout | 标准输出 |
2 | stderr | 标准错误 |
重定向输出
假设您要将date命令的输出保存到文件中。
尝试:
$ command > output.txt $ date > today.txt
使用cat命令查看today.txt文件的包含,运行:
$ cat today.txt
在上面的示例中,将创建一个名为today.txt的文件,如果您执行命令date并执行它,它将包含日期(您在屏幕上看到的内容)。
请注意,以上命令还将创建文件Today.txty(如果不存在),否则将其覆盖。
如果您想添加/添加,请尝试以下语法:
$ command1 >> filename $ command2 >> filename $ ls -l >> output.txt $ date >> output.txt
简而言之,我们可以简单地使用>
或者>>
符号将标准输出重定向到文件。
将标准错误流重定向到文件
以下将程序错误消息重定向到名为error.log的文件:
$ program-name 2> error.log $ command1 2> error.log
例如,使用grep命令在$HOME目录中进行递归搜索,并将所有错误(stderr)重定向到文件名grep-errors.txt,如下所示:
$ grep -R 'MASTER' $HOME 2> /tmp/grep-errors.txt $ cat /tmp/grep-errors.txt
输出示例:
grep: /home/Hyman/.config/google-chrome/SingletonSocket: No such device or address grep: /home/Hyman/.config/google-chrome/SingletonCookie: No such file or directory grep: /home/Hyman/.config/google-chrome/SingletonLock: No such file or directory grep: /home/Hyman/.byobu/.ssh-agent: No such device or address
将标准错误(stderr)和stdout重定向到文件
使用以下语法:
$ command-name &>file
我们也可以使用以下语法:
$ command > file-name 2>&1
我们也可以将stderr和stdout都写到两个不同的文件中。
让我们尝试之前的grep命令示例:
$ grep -R 'MASTER' $HOME 2> /tmp/grep-errors.txt 1> /tmp/grep-outputs.txt $ cat /tmp/grep-outputs.txt
将stderr重定向到stdout到文件或者其他命令
这是另一个有用的示例,其中stderr和stdout都发送到more命令而不是文件:
# find /usr/home -name .profile 2>&1 | more
将stderr重定向到stdout
使用以下命令:
$ command-name 2>&1 $ command-name > file.txt 2>&1 ## bash only ## $ command2 &> filename $ sudo find / -type f -iname ".env" &> /tmp/search.txt
重定向从左到右。
因此,顺序很重要。
例如:
command-name 2>&1 > file.txt ## wrong ## command-name > file.txt 2>&1 ## correct ##
如何在Bash脚本中将stderr重定向到stdout
在AWS/Linode服务器中创建时,用于更新VM的示例Shell脚本:
#!/usr/bin/env bash # Author - theitroad under GPL v2.x+ # Debian/Ubuntu Linux script for EC2 automation on first boot # ----------------------------------------------------------- # My log file - Save stdout to $LOGFILE LOGFILE="/root/logs.txt" # My error file - Save stderr to $ERRFILE ERRFILE="/root/errors.txt" # Start it printf "Starting update process ... \n" 1>"${LOGFILE}" # All errors should go to error file apt-get -y update 2>"${ERRFILE}" apt-get -y upgrade 2>>"${ERRFILE}" printf "Rebooting cloudserver ... \n" 1>>"${LOGFILE}" shutdown -r now 2>>"${ERRFILE}"
我们的最后一个示例使用exec命令和FD以及trap和自定义bash函数:
#!/bin/bash # Send both stdout/stderr to a /root/aws-ec2-debian.log file # Works with Ubuntu Linux too. # Use exec for FD and trap it using the trap # See bash man page for more info # Author: theitroad under GPL v2.x+ # -------------------------------------------- exec 3>&1 4>&2 trap 'exec 2>&4 1>&3' 0 1 2 3 exec 1>/root/aws-ec2-debian.log 2>&1 # log message log(){ local m="$@" echo "" echo "*** ${m} ***" echo "" } log "$(date) @ $(hostname)" ## Install stuff ## log "Updating up all packages" export DEBIAN_FRONTEND=noninteractive apt-get -y clean apt-get -y update apt-get -y upgrade apt-get -y --purge autoremove ## Update sshd config ## log "Configuring sshd_config" sed -i'.BAK' -e 's/PermitRootLogin yes/PermitRootLogin no/g' -e 's/#PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config ## Hide process from other users ## log "Update /proc/fstab to hide process from each other" echo 'proc /proc proc defaults,nosuid,nodev,noexec,relatime,hidepid=2 0 0' >> /etc/fstab ## Install LXD and stuff ## log "Installing LXD/wireguard/vnstat and other packages on this box" apt-get -y install lxd wireguard vnstat expect mariadb-server log "Configuring mysql with mysql_secure_installation" SECURE_MYSQL_EXEC=$(expect -c " set timeout 10 spawn mysql_secure_installation expect \"Enter current password for root (enter for none):\" send \"$MYSQL\r\" expect \"Change the root password?\" send \"n\r\" expect \"Remove anonymous users?\" send \"y\r\" expect \"Disallow root login remotely?\" send \"y\r\" expect \"Remove test database and access to it?\" send \"y\r\" expect \"Reload privilege tables now?\" send \"y\r\" expect eof ") # log to file # echo " $SECURE_MYSQL_EXEC " # We no longer need expect apt-get -y remove expect # Reboot the EC2 VM log "END: Rebooting requested @ $(date) by $(hostname)" reboot
还要将stderr和stdout都发送到终端和日志文件吗?
尝试按如下所示使用tee命令:
command1 2>&1 | tee filename
这也是内部shell脚本的使用方法:
#!/usr/bin/env bash { command1 command2 | do_something } 2>&1 | tee /tmp/outputs.log
总结
在本快速教程中,您了解了三个文件描述符stdin,stdout和stderr。
我们可以使用这些Bash描述符将stdout/stderr重定向到文件,反之亦然。
运算符 | 描述 | 示例 |
---|---|---|
command> filename | 将标准输出重定向到文件filename。 | date> output.txt |
command >> filename | 重定向并将stdout追加到文件文件名。 | ls -l >> dirs.txt |
命令2>文件名 | 将stderr重定向到文件文件名。 | du -ch/snaps/2> space.txt |
命令2 >>文件名 | 重定向stderr并将其追加到文件文件名。 | awk'{print $4}'input.txt 2 >> data.txt |
command&> filenamecommand> filename 2>&1 | 将stdout和stderr都重定向到文件名。 | grep -R foo/etc /&> out.txt |
命令&>>文件名命令>>文件名2>&1 | 将stdout和stderr都追加到文件名中。 | whois domain >> log.txt |