Shell编程笔记

Linux doc  2011 by: zollty

(如无特殊说明,本文所有的shell都是基于bash shell,而非dash sh)


有些linux的sh指向bash,两者等价,但有些则不一样。两者的区别参见:

https://www.cnblogs.com/macrored/p/11548347.html

https://www.jianshu.com/p/762d4cccee7e


布尔类型的定义和判断

the_world_is_flat=true
# …do something interesting…
if [ "$the_world_is_flat" = true ] ; then
    echo 'Be careful not to fall off!'
fi


字符串按位数截取

语法:${string: start :length}

例如:

url="c.zollty.com"
echo ${url: 2: 6}
# 结果为zollty


字符串正则表达式替换、分割

替换格式:${string//old/new}

示例如下:

#!/bin/bash
 
string="hello,shell,split,test"  
array=(${string//,/ })  
 
for var in ${array[@]}
do
   echo $var
done

再举个例子:string="hello=shell",将 ‘=’ 替换成 ‘,’ 如下

${string/=/,}


读懂下面代码:

#!/bin/bash
for i in `seq 1 10`; do
  node main.js && s=$? && break || s=$?;
  echo "Tried $i times. Waiting 5 secs...$?";
  sleep 5;
done;(exit $s)

知识点:$?

$?代表上一次命令的执行状态,成功则为0,失败则不为0(通常为1或2)

知识点:exit n  (n=0,1,2...)

n=0 代表正常退出,否则不正常退出。

知识点:与和非(&&和||)

aa && bb:代表左边的命令aa执行成功后,才执行右边的命令bb

aa || bb:和&&相反,左边的aa执行失败后,才执行右边的bb

上面的例子为 aa && bb && cc || dd 格式,意思是:

(aa && bb && cc) || dd,aa 成功执行bb,bb成功执行cc,无论aa、bb、cc哪个失败,dd都会执行。

注意:不要用 aa || bb && cc,因为 aa失败了,bb会执行,然后cc也会执行;但如果aa成功了,bb不会执行,但是cc任然会执行。所以无论aa成功或失败,cc都会执行,这不是我们想要的。如果想aa成功时不执行cc,则应写成:

aa || (bb; cc)

见下面的说明:

知识点:shell 小括号、花括号

(aaa; bbb; ccc) 的意思是将多个命令作为一个整体执行,新开一个shell进程执行括号里面的脚本。

如果换成{aaa; bbb; ccc},就是在当前进程中执行。

两者的区别:(重要!!)

()只是对一串命令重新开一个子shell进行执行
{}对一串命令在当前shell执行
()和{}都是把一串的命令放在括号里面,并且命令之间用;号隔开
()最后一个命令可以不用分号
{}最后一个命令要用分号
{}的第一个命令和左括号之间必须要有一个空格
()里的各命令不必和括号有空格
()和{}中括号里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里的所有命令。


现学现用:我们想让npm install执行失败后,打印出log信息,然后再退出,怎么办?

答案:

npm install || s=$?
if [ $s ]; then
  cat /root/.npm/_logs/*.log
  exit $s
fi
echo 'ok'

或者简写为
npm install || { s=$?; cat /root/.npm/_logs/*.log; exit $s}
echo 'ok'

或者简写为
set -e
npm install || (s=$?; cat /root/.npm/_logs/*.log; exit $s)
echo 'ok'

注意后面那种写法,必须加上set -e,否则exit无法退出,后面的程序会继续执行。

不推荐最后那种写法。中间那种写法更合适,因为花括号是在当前进程中执行,exit会退出当前进程。而后面那种写法使用的小括号,是新开一个进程,这样如果不设置 set -e,当前进程就不会结束


bash的管道( | )问题

    /bin/sh -c wget -O - https://some.site | wc -l > /number

    this only evaluates the exit code of the last operation in the pipe to determine success. 

    上例中只要 wc -l 命令成功,build就成功了,即使 wget 命令失败了。

    If you want the command to fail due to an error at any stage in the pipe, 设置 set -o pipefail && to ensure that an unexpected error prevents the build from inadvertently succeeding. For example:

    set -o pipefail && wget -O - https://some.site | wc -l > /number

    注意:不是所有的 shells 都支持 -o pipefail 选项:比如 the dash shell on Debian-based images, 

    建议使用下面的格式来显式声明/bin/bash 设置 pipefail 选项:

    /bin/bash -c set -o pipefail && wget -O - https://some.site | wc -l > /number


bash的set -e

    set -e的意思是,根据每一个子命令的返回结果(exit状态码),来确定是否退出,如果状态码不为0,则退出整个进程。

    注意,通常不这样设置,因为某个子命令的状态码不为0,不代表这个命令执行异常。例如diff命令

    diff pom.xml pom.xml2

    如果两个pom.xml不相同,则diff返回的状态码不为0,如果设置了 set -e,整个shell脚本就会退出。实际上diff不同是我们预料的结果,不应该退出shell进程。我曾经就被这个问题坑过!!

    解决方案(重要实践经验!):设置set -e,同时在不希望exit非0退出的地方加上“||”,例如:

echo 'xxx'
diff aa.sh  bb.sh || { s=$?; echo 'aa and bb is diffrent'; exit $s; }
echo 'yyyy'



获取参数

1、$n(n=1,2,3...) 代表获取第n个参数。

2、start.sh "$@" 将所有参数(空格分割)原封不动传给 start.sh

3、start.sh "${@:2}" 将第一个除外的所有参数(空格分割)原封不动传给 start.sh


Linux的$?特殊含义:

  • $$:Shell本身的PID(ProcessID,即脚本运行的当前 进程ID号)

  • $!:Shell最后运行的后台Process的PID(后台运行的最后一个进程的 进程ID号)

  • $?:最后运行的命令的结束代码(返回值)即执行上一个指令的返回值 (显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误)

  • $-:显示shell使用的当前选项,与set命令功能相同

  • $*:所有参数列表。如"$*"用「...」括起来的情况,以"$1 $2 … $n"的形式输出所有参数,此选项参数可超过9个。

  • $@:所有参数列表。如"$@"用「...」括起来的情况,以"$1" "$2" … "$n" 的形式输出所有参数。跟$*类似,但是可以当作数组用

  • $#:添加到Shell的参数个数

  • $0:Shell本身的文件名


+ (点击以下标题显示正文内容)

if-判断

+ (点击以下标题显示正文内容)

在 Shell 脚本中调用另一个 Shell 脚本的三种方式

+ (点击以下标题显示正文内容)

awk的用法

© 2009-2020 Zollty.com 版权所有。渝ICP备20008982号