Shell脚本学习笔记

shell脚本就是将完成一个任务的所有命令按照执行的先后顺序,自上而下写入到一个文本文件中,然后给予执行权限

shell脚本就是由shell命令组成的执行文件,将一些命令整合到一个文件中,进行处理业务逻辑,脚本不用编译即可运行。它通过解释器解释运行,所以速度相对来说比较慢。

一个shell脚本的组成通常为:

  • 解释环境
    #! 开头, 如
#!/bin/bash
  • 注释说明
    # 开头(单行注释), 如
#Script Description: install lftp
  • 执行代码

变量

变量类型

运行shell时,会同时存在三种变量:

  1. 局部变量:局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
  2. 环境变量:所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
  3. shell变量:shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
变量操作
  • 创建普通变量:name="test"(=两边不可有空格)

  • 创建只可函数体中使用的局部变量:local name="test"(使用local修饰的变量在函数体外无法访问,并且local只能在函数体内使用)

  • 使用变量:echo \$name 或者 echo \${name}(推荐使用大括号版)

  • 变量重新赋值:name="new_test" (将原值覆盖)

  • 只读变量:name="only_read" -> readonly name(使用readonly标识后的变量,不可被修改)

  • 删除变量:unset name;(删除之后不可访问,删除不掉只读变量)

字符串变量
  • 单引号
    单引号变量 var='test' ,只能原样输出,变量无效
    单引号中不能出现一个单独的单引号,转义也不可以

  • 双引号
    双引号变量 var="my name is ${name}" ,变量有效
    可出现转义符

  • 获取字符串长度
    ${}中使用 # 获取长度

name="test";
echo ${#name}; # 输出为4
  • 提取子字符串
    1:4 从第2个开始 往后截取4个字符
    ::4 从第一个字符开始 往后截取4个字符
name="this is my name";
echo ${name:1:4} #输出 is i
echo ${name::4} #输出 this
数组

bash只支持一维数组,不支持多维数组

  • 定义数组:
array_name=(li wang xiang zhang) (小括号做边界、使用空格分离)
  • 单独定义数组的元素:
arraypara[0]="w"; arraypara[3]="s" (定义时下标不连续也可以)
  • 赋值数组元素:
array_name[0]="zhao";
  • 获取数组元素:
array_name[0]="li"
array_name[3]="zhang"
echo ${array_name[0]} # 输出"li"
echo ${array_name[1]} # 输出" "
echo ${array_name[3]} # 输出"zhang"
echo ${array_name[@]} # 输出"li zhang" 输出数组所有元素,没有元素的下标省略
  • 取得元素个数:
${#array_name[@]} 或者 ${#array_name[*]}
  • 取得单个元素长度:
${#array_name[1]}

输出

echo仅用于字符串的输出,没有使用printf作为输出的移植性好,建议使用printf

printf

printf 不会像 echo 自动添加换行符,我们可以手动添加 \n
无大括号,直接以空格分隔

  • 格式:
printf format-string[arguments...]  #其中(format-string: 格式控制字符串、arguments: 参数列表)
  • 案例:
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
  • %s %c %d %f 都是格式替代符
    d:Decimal 十进制整数 对应位置参数必须是十进制整数,否则报错!
    s:String 字符串 对应位置参数必须是字符串或者字符型 否则报错
    c:Char 字符 对应位置参数必须是字符串或者字符型 否则报错
    f:Float 浮点 对应位置参数必须是数字型 否则报错

  • %-10s :指一个宽度为10个字符(-表示左对齐,没有则表示右对齐),任何字符都会被显示在10个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。

  • %-4.2f :指格式化为小数,宽度为4个字符,其中 .2指保留2位小数。

  • -n 不要在最后自动换行

  • -e 若字符串中出现以下字符,则特别加以处理,而不会将它当成一般字符输出

  • 转义符
    \a :警告字符,通常为ASCII的BEL字符
    \b :后退
    \c :抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略
    \f :换页(formfeed)
    \n :换行
    \r :回车(Carriage return)
    \t :水平制表符
    \v :垂直制表符
    \ :一个字面上的反斜杠字符
    \ddd :表示1到3位数八进制值的字符。仅在格式字符串中有效
    \0ddd :表示1到3位的八进制值字符

流程控制

和Java、PHP等语言不一样,sh的流程控制不可为空

如(以下为PHP流程控制写法):

<?php
if (isset($_GET["q"])) {
    search(q);
}
else {
    // 不做任何事情
}

在sh/bash里不能这么写,如果else分支没有语句执行,就不要写这个else

  • if
if
 condition
then
    command1
    command2
    ...
    commandN
fi
  • if else
if
 condition
then
    command1
    command2
    ...
    commandN
else
    command
fi
  • if else-if else
if
 condition1
then
    command1
elif
 condition2
then 
    command2
else
    commandN
fi
  • for
for var in item1 item2  ... itemN
do
    command1
    command2
    ...
    commandN
done
  • while condition
while
 condition
do
    command
done
  • while 无限循环
while :
do
    command
done
  • until
    until 循环执行一系列命令直至条件为 true 时停止。until 循环与 while 循环在处理方式上刚好相反。
until condition
do
    command
done
  • case
    Shell case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。case需要一个esac(就是case反过来)作为结束标记,每个case分支用右圆括号,用两个分号表示break,其中“;;”不是跳出循环,是不在去匹配下面的模式
    case语句格式如下:
case 值 in  
  模式1)
    command1
    command2    
    ...
    commandN    
    ;;  
  模式2)
    command1
    command2
    ...
    commandN    
    ;;
esac
  • 跳出循环

break :跳出本层循环

continue:跳出当前循环,继续下一次循环

函数

  • 函数定义
    可以带 function fun() 定义,也可以直接 fun() 定义,不带任何参数
[ function ] funname()
{
    action;
    [return int;]
}
  • 函数返回值
    return 字样可存在也可不存在
    return 只能为 return [0-255],此处的返回可作为函数执行的状态,通过 $? 获取的便是这个返回值
    如果不加 return ,则默认最后一条语句的执行状态所为函数执行状态的返回值,如果最后一条语句执行成功,则 $? 为0,否则不为0

输入输出重定向

一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:

  • 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
  • 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
  • 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。

默认情况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file。如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:

输入重定向

bash.sh < file  #将脚本的输入重定向到file,由file提供参数

输出重定向

bash.sh > file  #将脚本的输出数据重定向到file中,覆盖数据

bash.sh >> file  #将脚本的输出数据重定向到file中,追加数据

command >> file 2>&1  #将 stdout 和 stderr 合并后重定向到 file

读取外部输入

命令:read arg (脚本读取外部输入并赋值到变量上)
在shell脚本执行到上述命令时,停止脚本执行并等待外部输入,将外部输入赋值到arg变量上,继续执行脚本

文件引用

引用其他的文件之后,可以使用其变量、函数等等,相当于将引用的文件包含进了当前文件
两种方式:

. filepath\filename
source filepath\filename

长句换行

在shell中为避免一个语句过长,可以使用 \ 进行换行
使用 \ 换行,在脚本执行过程中还是当做一行一个语句执行,不同于enter直接换行
注意:\ 前添加一个空格,\ 后无空格直接换行。

/mysql/bin/mysql \
-h test_host  -P 000 \
-u test_user -ptest_password ;

shell操作mysql

下面案例为登录mysql,并选择操作数据库,之后进行导入数据

/mysql/mysql/bin/mysql \
 -h test_host  -P 000 \
 -u test_user -p test_password \
 -e "use test_database; source data_faile; " # -e 代表执行sql语句

-u 用户名
-p 用户密码
-h 服务器ip地址
-D 连接的数据库
-N 不输出列信息
-B 使用tab键 代替 分隔符
-e 执行的SQL语句

退出脚本
命令:exit

在退出脚本时使用不同的错误码,这样可以根据错误码来判断发生了什么错误。
在绝大多数 shell 脚本中,exit 0 表示执行成功,exit 1 表示发生错误。对错误与错误码进行一对一的映射,这样有助于脚本调试。

命令:set-e 和 set+e
set -e 表示从当前位置开始,如果出现任何错误都将触发exit。相反,set +e表示不管出现任何错误继续执行脚本。
如果脚本是有状态的(每个后续步骤都依赖前一个步骤),那么请使用set -e,在脚本出现错误时立即退出脚本。如果要求所有命令都要执行完(很少会这样),那么就使用set +e

shell脚本调试

检查脚本是否有语法错误 -n:bash -n script_name.sh
执行并调试 Shell 脚本 -x: bash -x script_name.sh
count_odd_number.sh 脚本案例:

#!/usr/bin.env bash

# 用于计算数组中奇数的和
# @author liyangyang
# @time 2019/09/17

sum=0
for num in 1 2 3 4;
do
    re=${num}%2
    if(( ${re} == 1 ));
    then
        sum=$[${sum}+${num}]    
    fi
done
echo ${sum}

首先检查有无语法错误:

bash -n count_odd_number.sh

没有输出,说明没有错误,开始实际调试:

bash -x count_odd_number.sh

调试结果如下:

+ sum=0
+ for num in 1 2 3 4
+ re=1%2
+ ((  1%2 == 1  ))
+ sum=1
+ for num in 1 2 3 4
+ re=2%2
+ ((  2%2 == 1  ))
+ for num in 1 2 3 4
+ re=3%2
+ ((  3%2 == 1  ))
+ sum=4
+ for num in 1 2 3 4
+ re=4%2
+ ((  4%2 == 1  ))
+ echo 4
4

其中的输出显示了程序执行的每一步,通过观察程序执行的步骤是否满足预期从而达到调试的效果
带有 + 表示的是 Shell 调试器的输出,不带 + 表示程序的输出。

本文借鉴:
https://mp.weixin.qq.com/s?__biz=MzUyODg4Nzk2MQ==&mid=2247511000&idx=7&sn=b659716090aabeb413994ebec2e973a7&chksm=fa6b922ecd1c1b38dbea0815a4ffa2debcabe99abbb789b7f6528ecd47ce71dd2f8308dd3ada&scene=27#wechat_redirect

https://www.runoob.com/linux/linux-shell-process-control.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容