linux mysql 错误重定向,linux输出错误重定向 总结

命令会将stdin重定向到文件中. 从这句开始, 后边的输入就都来自于这个文件了, 而不是标准输入了(通常都是键盘输入). 这样就提供了一种按行读取文件的方法, 并且可以使用 和/或 来对每一行进行分析.

Example 16-1. 使用exec重定向标准输入1 #!/bin/bash

2 # 使用'exec'重定向标准输入.

3

4

5 exec 6

6 # 保存了stdin.

7

8 exec < data-file # stdin被文件"data-file"所代替.

9

10 read a1 # 读取文件"data-file"的第一行.

11 read a2 # 读取文件"data-file"的第二行.

12

13 echo

14 echo "Following lines read from file."

15 echo "-------------------------------"

16 echo $a1

17 echo $a2

18

19 echo; echo; echo

20

21 exec 0

22 # 现在将stdin从fd #6中恢复, 因为刚才我们把stdin重定向到#6了,

23 #+ 然后关闭fd #6 ( 6

24 #

25 #

26

27 echo -n "Enter data "

28 read b1 # 现在"read"已经恢复正常了, 就是从stdin中读取.

29 echo "Input read from stdin."

30 echo "----------------------"

31 echo "b1 = $b1"

32

33 echo

34

35 exit 0

同样的, exec >filename 命令将会把stdout重定向到一个指定的文件中. 这样所有的命令输出就都会发向那个指定的文件, 而不是stdout.

Example 16-2. 使用exec来重定向stdout1 #!/bin/bash

2 # reassign-stdout.sh

3

4 LOGFILE=logfile.txt

5

6 exec 6>&1 # 将fd #6与stdout相连接.

7 # 保存stdout.

8

9 exec > $LOGFILE # stdout就被文件"logfile.txt"所代替了.

10

11 # ----------------------------------------------------------- #

12 # 在这块中所有命令的输出就都发向文件 $LOGFILE.

13

14 echo -n "Logfile: "

15 date

16 echo "-------------------------------------"

17 echo

18

19 echo "Output of "ls -al" command"

20 echo

21 ls -al

22 echo; echo

23 echo "Output of "df" command"

24 echo

25 df

26

27 # ----------------------------------------------------------- #

28

29 exec 1>&6 6>&- # 恢复stdout, 然后关闭文件描述符#6.

30

31 echo

32 echo "== stdout now restored to default == "

33 echo

34 ls -al

35 echo

36

37 exit 0

Example 16-3. 使用exec在同一脚本中重定向stdin和stdout1 #!/bin/bash

2 # upperconv.sh

3 # 将一个指定的输入文件转换为大写.

4

5 E_FILE_ACCESS=70

6 E_WRONG_ARGS=71

7

8 if [ ! -r "$1" ] # 判断指定的输入文件是否可读?

9 then

10 echo "Can't read from input file!"

11 echo "Usage: $0 input-file output-file"

12 exit $E_FILE_ACCESS

13 fi # 即使输入文件($1)没被指定

14 #+ 也还是会以相同的错误退出(为什么?).

15

16 if [ -z "$2" ]

17 then

18 echo "Need to specify output file."

19 echo "Usage: $0 input-file output-file"

20 exit $E_WRONG_ARGS

21 fi

22

23

24 exec 4

25 exec < $1 # 将会从输入文件中读取.

26

27 exec 7>&1

28 exec > $2 # 将写到输出文件中.

29 # 假设输出文件是可写的(添加检查?).

30

31 # -----------------------------------------------

32 cat - | tr a-z A-Z # 转换为大写.

33 # ^^^^^ # 从stdin中读取.Reads from stdin.

34 # ^^^^^^^^^^ # 写到stdout上.

35 # 然而, stdin和stdout都被重定向了.

36 # -----------------------------------------------

37

38 exec 1>&7 7>&- # 恢复 stout.

39 exec 0

40

41 # 恢复之后, 下边这行代码将会如期望的一样打印到stdout上.

42 echo "File "$1" written to "$2" as uppercase conversion."

43

44 exit 0

I/O重定向是一种避免可怕的问题的方法.

Example 16-4. 避免子shell1 #!/bin/bash

2 # avoid-subshell.sh

3 # Matthew Walker提出的建议.

4

5 Lines=0

6

7 echo

8

9 cat myfile.txt | while read line; # (译者注: 管道会产生子shell)

10 do {

11 echo $line

12 (( Lines++ )); # 增加这个变量的值

13 #+ 但是外部循环却不能存取.

14 # 子shell问题.

15 }

16 done

17

18 echo "Number of lines read = $Lines" # 0

19 # 错误!

20

21 echo "------------------------"

22

23

24 exec 3<> myfile.txt

25 while read line

26 do {

27 echo "$line"

28 (( Lines++ )); # 增加这个变量的值

29 #+ 现在外部循环就可以存取了.

30 # 没有子shell, 现在就没问题了.

31 }

32 done

33 exec 3>&-

34

35 echo "Number of lines read = $Lines" # 8

36

37 echo

38

39 exit 0

40

41 # 下边这些行是脚本的结果, 脚本是不会走到这里的.

42

43 $ cat myfile.txt

44

45 Line 1.

46 Line 2.

47 Line 3.

48 Line 4.

49 Line 5.

50 Line 6.

51 Line 7.

52 Line 8.

工作中需要构造一个数据传输工具,用来抓取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,不过初试之后感觉还没达到我的期望,也可能用的太少还没上手

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值