linux 错误信息 输出到管道,Linux管道只传到错误信息(stderr)——从一个小问题写起...

碰到问题

在自己编写的一个小脚本中,碰到这个一个小问题:

问题背景:

在脚本中多次导出数据,为了不用重复输入密码,在运行时,使用read读取用户输入,将密码存入变量。将mysql的命令中使用该变量,此时mysql提示在命令行直接输入密码不安全(其实他人无法看到密码):

# 脚本读取使用密码的一段为:

read -s -p "Enter Password: " passwd

mysql -uroot -S xxx -p$passwd -e "xxx" > xxx.sql

使用该脚本时,MySQL的提示为:

Enter password:

Warning: Using a password on the command line interface can be insecure.

第二行的提示其实没啥用,但是又不愿意使用 2>/dev/null 把所有错误信息都屏蔽掉。强迫症表示要干掉这条错误信息!

问题内容:

将标准输出(stdout),即导出的数据,重定向到文件保存。将输出的错误信息(stderr)中提示在命令行中使用密码不安全的Warning过滤掉(程序员只关心error,无视warning :)  ),同时,不影响其他错误信息的输出(不被过滤掉,也不会混到导出的数据中)。

求解过程

在Linux的bash中,可以将命令的标准输入(stdin)、标准输出(stdout)、标准错误输出(stderr)通过数据流重导向导入到文件,这可以方便我们记录很多信息。

管道的短处

在Linux中,管道”|“是经常使用的命令。可以很方便地利用一个命令来处理上一个命令的输出,准确的说是可以处理上一个命令的标准输出(stdout),管道并不能处理上一个命令的错误输出信息(stderr),如下:

# /tmp 目录下存在两个t开头的文件,不存在名为fff和sss的文件

# 这条命令的输出中包含两行标准输出(stdout)和两行标准错误输出(stderr)

[root /tmp ]$ ll t* fff sss

ls: cannot access fff: No such file or directory

ls: cannot access sss: No such file or directory

-rw-r--r-- 1 root root  29 Oct  8 15:11 t

-rwxr--r-- 1 root root 291 Sep 28 18:00 t.sh

# 无论grep过滤的关键词是什么,错误输出(stderr)的两行都在

[root /tmp ]$ ll t* fff sss | grep "fff"

ls: cannot access fff: No such file or directory

ls: cannot access sss: No such file or directory

[root /tmp ]$ ll t* fff sss | grep "t.sh"

ls: cannot access fff: No such file or directory

ls: cannot access sss: No such file or directory

-rwxr--r-- 1 root root 291 Sep 28 18:00 t.sh

数据流重导向和管道

当然,我们可以使用 2>&1 的数据流重定向,将错误输出(stderr)导向标准输出,这里很多人都知道:

# 在命令后加上 2>&1 就能使grep也能够过滤原来标准错误输出(stderr)的内容了

[root /tmp ]$ ll t* fff sss 2>&1 | grep "fff"

ls: cannot access fff: No such file or directory

[root /tmp ]$ ll t* fff sss 2>&1 | grep "t.sh"

-rwxr--r-- 1 root root 291 Sep 28 18:00 t.sh

如果这时又要将输出信息导出到文件的话,我们能从很多博客或者教材中看到这样的写法:

[root /tmp ]$ ll t* fff sss 1>/tmp/aa 2>&1

[root /tmp ]$ cat aa

ls: cannot access fff: No such file or directory

ls: cannot access sss: No such file or directory

-rw-r--r-- 1 root root  29 Oct  8 15:11 t

-rwxr--r-- 1 root root 291 Sep 28 18:00 t.sh

然而,这样的话,标准输出(stdout)和错误输出(stderr)都到一起了,如果我们要将两个输出分开到两个文件存放(对!人生苦短,就是要这么钻牛角尖和丧心病狂)。

用这个来模拟问题就是:标准输出(stdout)导出到/tmp/aa文件,错误信息(stderr)中只留下”fff“文件的这条,其他的过滤

问题解决方法

这样其实也很容易,具体的方法就是:将”1>/tmp/aa“和”2>&1“位置对调下!

[root /tmp ]$ ll t* fff sss 2>&1 1>/tmp/aa | grep "fff"

ls: cannot access fff: No such file or directory

[root /tmp ]$ cat aa

-rw-r--r-- 1 root root  29 Oct  8 15:11 t

-rwxr--r-- 1 root root 291 Sep 28 18:00 t.sh

[root /tmp ]$

这样,正确信息导出到/tmp/aa文件中,错误信息中过滤了不想要的信息。

自己总结

当时刚看到对调下就能产生这么大的差别时,心里默念了句:”哎呀,我x,还能这么用,我当初数据流白学了“

自己琢磨应该是这么回事:

2>&1  1>/tmp/aa

bash处理输出时,先碰到了”2>&1“,于是把错误信息(stderr)输出到标准输出(stdout)的位置(此时是默认位置,屏幕)。之后碰到了”1>/tmp/aa“,于是把原来的标准输出(stdout,不考虑被导过来的错误信息)输出到指定的文件(此时已被指定到/tmp/aa文件)

1>/tmp/aa  2>&1

bash处理输出时,先碰到了”1>/tmp/aa“,于是把标准输出(stdout)输出到指定文件(/tmp/aa文件)。之后碰到了”2>&1“,于是把错误信息(stderr)输出到标准输出(stdout)的位置(此时已被指定到/tmp/aa文件)

以上的也只是我自己瞎捉摸来帮助自己理解的。真实原因我不清楚,有个疑问就是:”1>/tmp/aa  2>&1“输出到文件的顺序并没有那么一致的顺序。按照我琢磨的,应该是先标准输出(stdout)后错误信息(stderr)。实际文件中的顺序为先错误信息(stderr)后标准输出(stdout)。

one more thing

如果有人知道具体怎么解释,或者有管道这方面的资料的话,欢迎告诉我

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值