如何利用 tee 命令调试shell脚本中的管道

目录
  • 实例
  • 执行脚本
  • 问题
  • 原因
  • 验证
  • 总结

实例

下面是一个简单的脚本,脚本中 processid 函数的作用是查询指定进程名字的进程ID,在管理linux服务器的过程中,这个是很常见的功能,processid 函数作用是利用多层管道命令查询进程ID,以下是测试脚本源码

#!/bin/sh

processid()
{
    ipid=$(ps -ef | grep -w $1 | grep -v grep | awk '{print $2}')
    echo $ipid
}

case "$1" in
    i)
       processid $2
      ;;
    *)
        echo "parameter error..$1"
      ;;
esac

执行脚本

我们执行这个脚本查询 zone9_log1 的进程ID,下面是执行的结果

[wanng@localhost ~]$ ./a.sh i zone9_log1
130530 144391 144392

为了和 zone9_log1 进程实际的进程ID对比,我们单独执行 ps -ef | grep -w zone9_log1 | grep -v grep | awk '{print $2}' 命令,执行结果如下:

[wanng@localhost ~]$ ps -ef | grep -w zone9_log1 | grep -v grep | awk '{print $2}'
130530

问题

同样的命令,确得到了不同的结果,我们在脚本中加入 tee 命令输出管道的中间结果,调整之后的的脚本如下:

processid()
{
    ipid=$(ps -ef | grep -w $1 | tee out1 | grep -v grep | tee out2 | awk '{print $2}') | tee out3
    echo $ipid
}

case "$1" in
    i)
       processid $2
      ;;
    *)
        echo "parameter error..$1"
      ;;
esac

再次执行脚本,本地会生成 out1 out2 out3 三个文件,记录这管道命令的中间结果,下面是脚本执行结果以及 out1 out2 out3 文件的内容

[wang@localhost ~]$ ./a.sh i zone9_log1
130530 144885 144886

[wang@localhost ~]$ cat out1
wang      130530      1  0 4月24 pts/10  00:07:47 ./zone9_log1 ./zone9_log1.lua
wang       144885 109338  0 20:45 pts/8    00:00:00 /bin/sh ./a.sh i zone9_log1
wang       144886 144885  0 20:45 pts/8    00:00:00 /bin/sh ./a.sh i zone9_log1
wang       144888 144886  0 20:45 pts/8    00:00:00 grep -w zone9_log1
[wang@localhost ~]$ cat out2
wang      130530      1  0 4月24 pts/10  00:07:47 ./zone9_log1 ./zone9_log1.lua
wang       144885 109338  0 20:45 pts/8    00:00:00 /bin/sh ./a.sh i zone9_log1
wang       144886 144885  0 20:45 pts/8    00:00:00 /bin/sh ./a.sh i zone9_log1
[wang@localhost ~]$ cat out3
130530
144885
144886
[wang@localhost ~]$ 

原因

执行脚本的时候,默认会创建一个新的shell(也即一个新的进程),上面的脚本 a.sh 就是在新的shell环境中执行的。从上面的测试结果可以看出,ps -ef | grep -w zone9_log1 命令的结果中包含了执行脚本身启动的进程和我们要查询的目标进程,我们只需要过滤掉脚本本身的进程,就可以得到准确的进程ID,调整之后的脚本如下(暂时先保留 tee命令输出的中间结果):

processid()
{
    ipid=$(ps -ef | grep -w $1 | grep -v $0 | tee out1 | grep -v grep | tee out2 | awk '{print $2}') | tee out3
    echo $ipid
}

case "$1" in
    i)
       processid $2
      ;;
    *)
        echo "parameter error..$1"
      ;;
esac

上面processid函数中 grep -v $0 作用是过滤掉脚本的名字,其中 $0 表示脚本的名字 ( a.sh )

验证

再次执行脚本,结果如下:

[wanng@localhost ~]$ ./a.sh i zone9_log1
130530

[wanng@localhost ~]$ cat out1
wanng      130530      1  0 4月24 pts/10  00:07:51 ./zone9_log1 ./zone9_log1.lua
wanng       146170 146168  0 21:11 pts/8    00:00:00 grep -w zone9_log1
[wanng@localhost ~]$ cat out2
wanng      130530      1  0 4月24 pts/10  00:07:51 ./zone9_log1 ./zone9_log1.lua
[wanng@localhost ~]$ cat out3
130530

从上面的测试结果中看出,最后输出的结果是正确的

总结

多层管道在shell脚本中是很常见的用法,使用起来也非常方便和高效的,但是脚本一旦出问题调试就会变得困难起来,合理的使用 tee 命令输出管道的中间结果,可以快速的定位问题所在

以上就是如何利用 tee 命令调试shell脚本中的管道的详细内容,更多关于tee 命令调试shell脚本中的管道的资料请关注我们其它相关文章!

(0)

相关推荐

  • Shell脚步攻略之管道重定向基础

    1.8.1 匿名管道"|" 管道符号意如其名,类似管道一样将管道入口的数据通过管道传递给管道出口. 管道是为了解决进程间通信问题而存在,它可以让两个进程之间的数据进行传递,将一个进程的输出数据传递给另一个进程作为其输入数据.管道左边是数据给予方,管道右边是数据接收方. 例如echo "abcd" | passwd --stdin username,表示将进程echo的输出结果"abcd"作为进程passwd的输入数据. 基本的管道符号及其用法很容

  • PowerShell入门教程之PowerShell管道介绍

    管道对于Shell来说是个化腐朽为神奇的东西,它极大地提高了在命令行上编程的能力.深入理解并熟练使用管道是PowerShell高手之路的必经阶段.没有管道,我们就不得不通过许多的变量来保存中间结果,虽然这是脚本和其他编译型语言的惯用伎俩,但对于战斗在命令行上的Shell而言,就是一件非常痛苦的事情. 管道模型 顾名思义,管道就是用管子将事物连接起来构成通道.从表面上看,管道是一串由管道符号(|)连接起来的一些命令.从功能来看,管道就像流水线,将上一个处理的结果,传送给下一个处理作为输入.由管道连

  • linux shell 管道命令(pipe)使用及与shell重定向区别

    看了前面一节:linux shell数据重定向(输入重定向与输出重定向)详细分析 估计还有一些朋友是头晕晕的,好复杂的重定向了.这次我们看下管道命令了.shell管道,可以说用法就简单多了. 管道命令操作符是:"|",它仅能处理经由前面一个指令传出的正确输出信息,也就是 standard output 的信息,对于 stdandard error 信息没有直接处理能力.然后,传递给下一个命令,作为标准的输入 standard input. 管道命令使用说明: 先看下下面图: comma

  • Windows Powershell过滤管道结果

    如果要过滤对象可以使用Where-Object:如果要过滤对象的属性,可以使用Select-Object:如果要自定义个性化的过滤效果可以使用ForEach-Object.最后如果想过滤重复的结果,可是使用Get-Uinque. 筛选管道结果中的对象 如果你只对管道结果的特定对象感兴趣,可是使用Where-Object对每个结果进行严格筛选,一旦满足你的标准才会保留,不满足标准的就会自动丢弃.例如你通过Get-service查看运行在机器上的当前服务,但是可能只关心哪些正在运行的服务,这时就可是

  • Shell脚本中管道的几种使用实例讲解

    管道经常用于拼接命令,通过管道可以执行一些复杂的数据处理操作.以下为在shell中使用管道处理数据的的几个实例 示例1:生成一个8位的随机密码 tr -dc A-Za-z0-9_ </dev/urandom | head -c 8 | xargs 示例2:查看系统中所有的用户名称,并按字母排序 awk -F: '{print $1}' /etc/passwd | sort 示例3:列出当前用户使用最多的5个命令(print的列数根据实际情况而定) history | awk '{print $2

  • Windows Powershell导出管道结果

    可以将管道的结果转换成文本输出,默认是Out-Default.可以通过Get-Command -verb out查看Powershell都有哪些输出的命令. 复制代码 代码如下: PS C:PowerShell> get-command -Verb out CommandType Name         Definition ----------- ----         ---------- Cmdlet      Out-Default  Out-Default [-InputObjec

  • PowerShell中终止管道的方法

    如果你能够提前知道你想从管道中获取元素的个数,可以使用Select-Object来终止流处理命令的的管道,这会节省很多时间. 下面的例子会从Windows文件夹下搜寻 explorer.exe示例,因为Select-Object语句可以在管道找到结果的那一瞬终止管道.否则,Get-ChildItem会递归的遍历所有子目录然后匹配出你想要的结果. 复制代码 代码如下: #requires -Version 3 Get-ChildItem -Path c:\Windows -Recurse -Fil

  • shell脚本一键同时推送代码至github和gitee的解决办法

    自己写的东西,要同时推送多个git地址,解决办法如下: 1.先要初始化你的git              进入自己的项目目录,然后执行 git  init cd /app/code/go-study git init 2.执行以下脚本: #!/bin/bash #author Oliver #since 2020-09-03 15:24:31 git remote rm origin #replace your git location git remote add origin 'https

  • PowerShell实现按条件终止管道的方法

    有时你可能想在管道运行在某个特定的条件下,终止管道.今天来演示一个比较新颖的方式,它适用于PowerShell 2.0或着更高版本.先看代码: filter Stop-Pipeline { param ( [scriptblock] $condition = {$true} ) if (& $condition) { continue } $_ } do { Get-ChildItem c:\Windows -Recurse -ErrorAction SilentlyContinue | Sto

  • PowerShell管道入门必看篇(管道例子大全)

    PowerShell的一个重中之重的功能就是管道(pipeline),本文从浅入深,一步一步详解管道的使用方法和例子,来看看有没有你所不知道的吧,如果全知道,恭喜你已经很厉害啦--适用于所有PowerShell应用小白与技术老鸟.另外欢迎各位技术大牛来补充讨论学习~ 1. 管道(pipeline)是什么 在Shell中一个重要的基本概念就是管道(pipeline),即在一组命令中,输出的命令结果成为下一个命令的输入参数.管道的概念与真实生活中的生产线比较相似:在不同的生产环节进行连续的再加工,如

随机推荐