Bash中使用管道时如何正确捕捉返回值

在Bash中,通过管道执行命令时,返回值只能反映出管道中最后一个命令的状态。本文介绍了如何利用`PIPESTATUS`环境变量和子shell来正确捕获管道中每个命令的返回值,特别是在数据传输工具中,如从FTP抓取日志并写入HDFS的场景。错误的解决方案如使用`exit`直接退出shell,而正确的做法是使用`() && exit`结构确保正确捕获并处理返回值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

工作中需要构造一个数据传输工具,用来抓取ftp前端机的web日志并直接写入HDFS,该工具直接作为hadoop mapreduce任务定时执行,所以最好不使用文件脚本以免去分发文件的繁琐,能一句命令搞定最好。


如何抓取ftp前端机的web日志并写入HDFS? 管道(pipe),命令如下:
wget $SRC_URL --limit-rate=%s --tries=1 -O - | hadoop fs -put - $DESTPATH
一行命令,可以直接当成-mapper的参数,不需要额外写文件脚本

可惜这个方法有问题,使用管道的话,整个命令的返回值是后半部分(hadoop fs -put - $DESTPATH)的返回值
当wget没有得到抓到任何内容返回失败时,整个命令返回0,错误没有捕捉到,

如何解决?
1. PIPESTATUS
PIPESTATUS是一个环境变量,数组类型,保存了PIPE中所有命令的返回值
PIPE命令成功结束后,判断PIPESTATUS[0]是否为零即可

2. 那怎么将这些逻辑整合到一条shell命令中?

正确解法(之一)需要使用到() && exit,先看看这些(), &&, ||的标准行为:

( list )
Placing a list of commands between parentheses causes a subshell to be created, and each of the commands in list to be executed in that subshell. Since the list is executed in a subshell, variable assignments do not remain in effect after the subshell completes.

expression1 && expression2   True if both expression1 and expression2 are true.
expression1 || expression2   True if either expression1 or expression2 is true.

 The && and || commands do not execute expression2 if the value of expression1 is sufficient to determine the return value of the entire conditional expression.

 

 

 

最后我的解决方案:
wget $SRC_URL --limit-rate=%s --tries=1 -O - | hadoop fs -put - $DESTPATH && ( exit ${PIPESTATUS[0]} )

其实在找到这个正确方法之前,还是走了不少弯路:

wget $SRC_URL --limit-rate=%s --tries=1 -O - | hadoop fs -put - $DESTPATH && exit ${PIPESTATUS[0]}
exit命令会直接退出当前shell,慎用!

wget $SRC_URL --limit-rate=%s --tries=1 -O - | hadoop fs -put - $DESTPATH && ( exit ${PIPESTATUS[0]} )
()的功能是新启动一个shell来运行括号里面的内容,这样exit的是()产生的shell,同时捕捉到了PIPESTATUS[0]

最后为了代码可读性(C++传染过来的毛病-_-!!), 擅自加了个括号:
( wget $SRC_URL --limit-rate=%s --tries=1 -O - | hadoop fs -put - $DESTPATH ) && ( exit ${PIPESTATUS[0]} )

这样反而又错了,由于左边的管道命令被封在一个新的shell里面,PIPESTATUS环境变量已经追踪不到里面的管道命令了!!标准的画蛇添足!

问题几经曲折之后终于解决,对shell编程知识的积累也多了一点!

PS:
感觉shell确实是一种严重依赖"技巧",并把取巧当成其设计理念的工具,而不是语言
shell不像一种完备的现代程序语言,拥有严格的语法和语义,严格直接意味着不容易出错,也不容易让用户误用,这其实是很重要的,也是我倾向使用的脚本环境
反观shell,很多本来应该属于语法的东西, 是通过某种方式取巧模拟出来的,比如很多关键字其实是个程序
所以在使用shell时,就需要额外小心,随时可能踩到地雷,当然不排除有高手将它用的出神入化,到了写出的脚本一般人都看不懂的地步。
开发实际的项目时,shell编程的使用最好限制在很小的范围内,比如仅仅是用来包装一下主程序和工具程序,最好不要用它来做功能实现

PS2:
也许Python加上强大的系统管理工具库可以创造一个比较完美的可编程shell来,比如ipython,不过初试之后感觉还没达到我的期望,也可能用的太少还没上手

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值