如何学到基本的shell 脚本信息

1) 热身

下面的例子展示了如何向脚本传递参数、脚本如何获取参数、if-else判断、变量的使用等基本内容。

#!/bin/bash  
if [[ $# -lt 1 ]]; then  
        echo "args count must > 1"  
        echo "Uage: bash +x example01.sh [args...]"  
        exit  
fi  
arg=$1  
if [[ $arg -gt 10 ]]; then  
        echo "$arg > 10"  
else  
        echo "$arg < 10"  
fi  

 

这个脚本的调用方式如下:

bash +x example01.sh 5  

 

2).数组、函数传参数,循环

下面的例子展示了数组、函数、循环等基本使用。

#!/bin/bash  
if [[ $# -lt 1 ]]; then  
    echo "args count must > 1"  
    echo "Uage: bash +x example01.sh [args...]"  
    exit  
fi  
args=$@  
for arg in $args; do  
    echo $arg  
done  
function fun() {  
    echo $1  
}  

fun "hello shell"  
fun2() {  
    echo "Linux"  
}  
fun2  

 

注意,函数fun中的$1,获取的是函数参数,不是脚本调用时传入的参数。$@ 是获取脚本调用时传入的参数列表。

3).while 循环以及其他几种循环、case、表达式expr的使用

#!/bin/bash  
if [[ $# -lt 1 ]]; then  
        echo "args count must > 1"  
        echo "Uage: bash +x example01.sh [args...]"  
        exit  
fi  
case $1 in  
        "install" )  
                echo "operation type is install"  
        ;;  
        "uninstall" )  
                echo "operation type is uninstall"  
        ;;  
        * )  
                echo "operation type is not support"  
        ;;  
esac  
for ((i=0;i<3;i++))  
do  
        if ((i==1))  
        then  
                continue  
        fi  
        echo $i  
done  
for i in `seq 5`  
do  
        echo "loop $i"  
done  

 

注意这里的case * 并不是所有,而是输入值不在case中,相当于default. 在循环中可以使用continue/break等关键字,非常类似java等其他语言的循环。

4).脚本之间互相引用

通过source 或者 . 的方式可以引用另一个脚本中的函数或者变量

first.sh

function fun(){  
    echo "i am from first."  
}  
file=first  
second.sh

. first.sh  
fun  
echo $file  

 

使用bash +x second.sh执行,在second.sh 中可以调用fun函数和使用file变量。

这里的.和source都可以实现引用first文件中的变量。注意: 如果同时引用了多个脚本的同一个变量名的变量,后面的值会覆盖前面的变量而不会报错。

5).关于错误处理

a)在shell中有一个变量 $? ,这个变量记录的是上次脚本执行的结果,如果正常结束则是0,否则是非0值;

b)如果在shell脚本中通过set -o errexit来实现遇到错误就退出,这样能够避免产生更多的错误;

c)在shell执行过程中如果出错,可以通过重定向的方式,输出到文件中,比如Command >> filename2>&1

6).字典

shell中的字典是非常好的数据结构,能够很方便地处理配置

#!/bin/bash  
set -o errexit  
hput(){  
    eval "hkey_$1"="$2"  
}  
hget(){  
    eval echo '${'"hkey_$1"'}'  
}  
hput k1 v1  
hget k1  
declare -A dic  
dic=([key1]="value1" [key2]="value2" [key3]="value3")  
echo ${dic["key1"]}  
# output all key  
echo ${!dic[*]}  
#outpull all value  
echo ${dic[*]}  
# access all  
for key in $(echo ${!dic[*]})  
do  
        echo "$key : ${dic[$key]}"  
done  

 

执行之后,输出如下:

v1  
value1  
key3 key2 key1  
value3 value2 value1  
key3 : value3  
key2 : value2  
key1 : value1  

 

7).文本处理

sed 命令能够对对文本进行操作。

比如有一个文件sedfile,内容如下:

1  
2  
3  
4  
5  

 

执行 "sed '1,3d' sedfile,则会输出4,5 两行,即对1,2,3行做了删除处理,注意这时文件里面并没有删掉这两行。

除了删除之外,还可以做替换操作。

root@ubuntu:~/codelab# sed 's/1/0/g' sedfile   
0  
2  
3  
4  
5  
root@ubuntu:~/codelab# cat sedfile   
1  
2  
3  
4  
5  

 

我们发现,在输出时,将1替换成了0;

文本处理还有一个非常强大的工具-awk

我们首先看看awk的基本处理-按照逗号(,)分割获取想要的文本;

root@ubuntu:~/codelab# cat awkfile   
this,is,a,awk,file  
this,is,a,awk,file  
root@ubuntu:~/codelab# cat awkfile | awk -F ',' '{print $0}'  
this,is,a,awk,file  
this,is,a,awk,file  
root@ubuntu:~/codelab# cat awkfile | awk -F ',' '{print $1}'  
this  
this  
root@ubuntu:~/codelab#   

 

这里我们可以看到awk可以按照任意形式分割文本,然后输出;

8).特殊变量和值

下列变量通常具有固定意义

$#    表示变量的个数,常用于循环  
$@    当前命令行所有参数。置于双引号中,表示个别参数  
$*    当前命令行所有参数。置于双引号中,表示将命令行所有参数当初一个单独参数  
$-(连字号)    在引用数给予Shell的选项  
$?    表示上一个命令退出的状态  
$$    表示当前进程编号  
$0    表示当前程序名称  
$!    表示最近一个后台命令的进程编号  
$HOME    表示当前用户根目录  
$IFS    表示内部的字段分隔符  
$LANG    当前locale默认名称  
$PATH    环境变量  
$PPID    父进程编号  
$PWD    当前工作目录  

 

下列特殊值可以帮助排查问题

0    成功退出  
>0    退出失败  
1-125    命令退出失败,失败返回的相关值由程序定义(譬如,程序内退出只执行 exit 2,则返回为2)  
126    命令找到了,但无法执行  
127    命令找不到  
>128    命令因受到信号而死亡  

 

9.定时任务

windows系统下有定时任务,在linux系统上也一样有定时任务。使用系统自带的crontab即可实现;

我的系统上执行 cat /etc/crontab的输出如下:

root@ubuntu:~/codelab# cat /etc/crontab   
# /etc/crontab: system-wide crontab  
# Unlike any other crontab you don't have to run the `crontab'  
# command to install the new version when you edit this file  
# and files in /etc/cron.d. These files also have username fields,  
# that none of the other crontabs do.  
SHELL=/bin/sh  
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin  
# m h dom mon dow user  command  
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly  
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )  
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )  
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )  
#  

 

从这里我们可以看出cron是如何使用的,这里设定了cron使用shell,下面是命令的设置方式。

1 minute: 表示分钟,可以是从0到59之间的任何整数。  
2 hour:表示小时,可以是从0到23之间的任何整数。  
3 day:表示日期,可以是从1到31之间的任何整数。  
4 month:表示月份,可以是从1到12之间的任何整数。  
5 week:表示星期几,可以是从0到7之间的任何整数,这里的0或7代表星期日。  
6 command:要执行的命令,可以是系统命令,也可以是自己编写的脚本文件。  

 

我们可以使用如下一些基础命令;

1 usage:  crontab [-u user] file  
2     crontab [ -u user ] [ -i ] { -e | -l | -r }  
3         (default operation is replace, per 1003.2)  
4     -e  (edit user's crontab)  
5     -l  (list user's crontab)  
6     -r  (delete user's crontab)  
7     -i  (prompt before deleting user's crontab)  

 

10).技巧

a)判断参数是否是数字。

#!/bin/sh  
#1. $1是脚本的第一个参数,这里作为awk命令的第一个参数传入给awk命令。  
#2. 由于没有输入文件作为输入流,因此这里只是在BEGIN块中完成。  
#3. 在awk中ARGV数组表示awk命令的参数数组,ARGV[0]表示命令本身,ARGV[1]表示第一个参数。  
#4. match是awk的内置函数,返回值为匹配的正则表达式在字符串中(ARGV[1])的起始位置,没有找到返回0。  
#5. 正则表达式的写法已经保证了匹配的字符串一定是十进制的正整数,如需要浮点数或负数,仅需修改正则即可。  
#6. awk执行完成后将结果返回给isdigit变量,并作为其初始化值。  
#7. isdigit=`echo $1 | awk '{ if (match($1, "^[0-9]+$") != 0) print "true"; else print "false" }' `  
#8. 上面的写法也能实现该功能,但是由于有多个进程参与,因此效率低于下面的写法。  
isdigit=`awk 'BEGIN { if (match(ARGV[1],"^[0-9]+$") != 0) print "true"; else print "false" }' $1`  
if [[ $isdigit == "true" ]]; then  
      echo "This is numeric variable."  
      number=$1<pre code_snippet_id="1930260" snippet_file_name="blog_20161015_17_9421840" name="code" class="plain">fi</pre>  

 

b) 根据系统给变量赋值,确保可移植性

 1 #1. 通过uname命令获取当前的系统名称,之后再根据OS名称的不同,给PING变量赋值不同的ping命令的全称。  
 2 osname=`uname -s`  
 3 #2. 可以在case的条件中添加更多的操作系统名称。  
 4 case $osname in  
 5       "Linux")  
 6 PING=/usr/sbin/ping ;;  
 7       "FreeBSD")  
 8 PING=/sbin/ping ;;  
 9       "SunOS")  
10 PING=/usr/sbin/ping ;;  
11       *)  
12           ;;  
13 esac  

 

总结

这些只是shell中的最基础部分,掌握了以上这些,基本够入门了,shell 其实是一种非常高效、强大的语言,不断学习和积累一定会越来越熟练。

posted @ 2022-10-27 18:00  划边逅  阅读(32)  评论(0编辑  收藏  举报