shell编程学习

本文介绍Shell脚本的调试技巧,包括多种调试参数的使用方法,环境变量与普通变量的区别,以及如何管理和操作变量。同时涵盖了常用的运算符、管道命令和条件判断等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2023.03.14 辛苦排版了一会想起来之前有大佬早就整理过了,链接供参考.以下为原文


先简单写一点,以后在整理
记性不好,看完就忘…

sh bash脚本编程调试

当我们写c或其他程序时,都有调试这一技能,调试可以说是很重要的了…能节约你的时间,shell脚本也有调试…
两种方式–执行时添加参数 脚本里添加参数

参数含义
-n不执行脚本,仅检查是否有语法错误
-v执行脚本前,把脚本内容输出到屏幕
-x将执行时的内容输出到屏幕
-e执行出现错误时退出
  • 执行时添加

假如现在要执行的脚本叫做test.sh,那么
bash -n test.sh可以检查脚本语法是否有错,无错误没有任何输出,echo $?可以得0.同理,其他的参数也一样.
另外这些参数可以组合使用–但是,当加入n后,脚本就不会执行了,所以-nxx将不会起作用…

  • 脚本里添加

脚本第一行一般都是

#!/bin/bash
...#脚本内容
...

这种指定哪个解释器执行脚本的语句,这样,参数可以跟在后面:

#!/bin/bash -n
...#脚本内容
...

这样就可以检查语法错误了
另外还可以针对某一段执行,如:

#!/bin/bash

...#段1
...
set -n#开始检查语法
...#段2
...
set +n#停止检查

这样就可以只针对段2检查语法错误,-n开始,+n停止,另外的x,v也是一样
需要注意的是,若采用#!/bin/bash -e这种形式,那么如果执行脚本的时候使用的不是指定的shell,比如采用sh test.sh,那么设置的-e参数不起作用,但是set -e可以生效。

环境变量

直接问chatgpt了
Q:shell的环境变量,和普通变量有什么不同?如果定义了一个变量,与运行的程序一同执行或者不一同执行有什么区别?

GPT-3 A:shell的环境变量是用来定义系统的运行环境的,它们可以被系统和所有的子程序共享,而普通变量只能在当前shell中使用。

如果定义了一个变量,与运行的程序一同执行时,这个变量可以在程序中使用;如果不一同执行时,程序中就不能使用这个变量。
GPT-4 A:
根据网上的搜索结果,shell变量和环境变量的区别是:

shell变量只在当前的shell中有效,用于设置短期的工作条件。环境变量对所有从shell启动的进程都有效,用于传递信息。
shell变量可以用export命令转换为环境变量。环境变量可以用unset命令取消。
如果定义了一个变量,与运行的程序一同执行或者不一同执行有什么区别?这取决于你是否将该变量导出为环境变量。如果是,那么该变量就可以被程序访问;如果不是,那么该变量就只能在当前的shell中使用。
了解详细信息:
1. stackoverflow.com
2. digitalocean.com
3. askubuntu.com

看来还是gpt-4好用,哈哈
我会关心这个问题是之前交叉编译的时候,指定CC,但是不起作用,故有此一问。

运算符

今天看脚本把&& ||和c里面的逻辑运算符混了…

符号意义
cmd1&&cmd2cmd1执行成功(返回0),cmd2才执行
cmd1||cmd2cmd1执行成功(返回0),cmd2不执行

这里说的返回0,是一个环境变量$?,总之不能跟逻辑与或混了…
bash支持的运算符如下,假定变量 a 为 10,变量 b 为 20::

  • 数学运算符
运算符说明举例
+加法`expr $a + $b` 结果为 30。
-减法`expr $a - $b` 结果为 -10。
*乘法`expr $a * $b` 结果为 200。
/除法`expr $b / $a` 结果为 2。
%取余`expr $b % $a` 结果为 0。
=赋值a=$b 把变量 b 的值赋给 a。
==相等用于比较两个数字,相同则返回 true。 [ $a == $b ] 返回 false。
!=不相等用于比较两个数字,不相同则返回 true。 [ $a != $b ] 返回 true。
  • 关系运算符
运算符说明举例
-eq检测两个数是否相等,相等返回 true。[ $a -eq $b ] 返回 false。
-ne检测两个数是否不相等,不相等返回 true。[ $a -ne $b ] 返回 true。
-gt检测左边的数是否大于右边的,如果是,则返回 true。[ $a -gt $b ] 返回 false。
-lt检测左边的数是否小于右边的,如果是,则返回 true。[ $a -lt $b ] 返回 true。
-ge检测左边的数是否大于等于右边的,如果是,则返回 true。[ $a -ge $b ] 返回 false。
-le检测左边的数是否小于等于右边的,如果是,则返回 true。[ $a -le $b ] 返回 true。
  • 布尔运算符
运算符说明举例
!非运算,表达式为 true 则返回 false,否则返回 true。[ ! false ] 返回 true。
-o或运算,有一个表达式为 true 则返回 true。[ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a与运算,两个表达式都为 true 才返回 true。[ $a -lt 20 -a $b -gt 100 ] 返回 false。
  • 逻辑运算符
运算符说明举例
&&逻辑的 AND[[ $a -lt 100 && $b -gt 100 ]] 返回 false
||逻辑的 OR[[ $a -lt 100 || $b -gt 100 ]] 返回 true
  • 字符串运算符
运算符说明举例
=检测两个字符串是否相等,相等返回 true。[ $a = $b ] 返回 false。
!=检测两个字符串是否不相等,不相等返回 true。[ $a != $b ] 返回 true。
-z检测字符串长度是否为0,为0返回 true。[ -z $a ] 返回 false。
-n检测字符串长度是否不为 0,不为 0 返回 true。[ -n “$a” ] 返回 true。
$检测字符串是否不为空,不为空返回 true。[ $a ] 返回 true。
  • 文件测试运算符
选项意义
[ -a FILE ]如果 FILE 存在则为真。
[ -b FILE ]如果 FILE 存在且是一个块特殊文件则为真。
[ -c FILE ]如果 FILE 存在且是一个字特殊文件则为真。
[ -d FILE ]如果 FILE 存在且是一个目录则为真。
[ -e FILE ]如果 FILE 存在则为真。
[ -f FILE ]如果 FILE 存在且是一个普通文件则为真。
[ -g FILE ]如果 FILE 存在且已经设置了SGID则为真。
[ -h FILE ]如果 FILE 存在且是一个符号连接则为真。
[ -k FILE ]如果 FILE 存在且已经设置了粘制位则为真。
[ -p FILE ]如果 FILE 存在且是一个名字管道(F如果O)则为真。
[ -r FILE ]如果 FILE 存在且是可读的则为真。
[ -s FILE ]如果 FILE 存在且大小不为o则为真。
[ -t FD ]如果文件描述符 FD 打开且指向一个终端则为真。
[ -u FILE ]如果 FILE 存在且设置了SUID (set user ID)则为真。
[ -w FILE ]如果 FILE 如果 FILE 存在且是可写的则为真。
[ -x FILE ]如果 FILE 存在且是可执行的则为真。
[ -O FILE ]如果 FILE 存在且属有效用户ID则为真。
[ -G FILE ]如果 FILE 存在且属有效用户组则为真。
[ -L FILE ]如果 FILE 存在且是一个符号连接则为真。
[ -N FILE ]如果 FILE 存在 且已被修改如果ied since it was last read则为真。
[ -S FILE ]如果 FILE 存在且是一个套接字则为真。
[ FILE1 -nt FILE2 ]如果 FILE1比 FILE2 要新 , 或者 FILE1 存在而 FILE2 不存在则为真。
[ FILE1 -ot FILE2 ]如果 FILE1 比 FILE2 要老, 或者 FILE2 存在且 FILE1 不存在则为真。
[ FILE1 -ef FILE2 ]如果 FILE1 和 FILE2 指向相同的设备和节点号则为真。
[ -o OPTIONNAME ]如果 shell选项 “OPTIONNAME” 开启则为真。

变量

命令意义
read从键盘读取变量值
array数组
declare声明变量类型
echo $var查看变量内容
unset $var取消设定变量
set查看所有变量
export var将自定义变量变为环境变量,也就是子程序可以调用此变量了 注1

注1:source或.执行脚本即当前shell执行,不是在子程序里执行,可以做到立即生效的作用
比较有用的几个环境变量:

变量意义
$HOME代表用户的家目录
$SHELL目前正在使用的shell
$PATH可执行文件搜索路径
$LANG语言变量
$RANDOM随机数变量
$PS1提示字符的设定
$$这个程式的PID(脚本运行的当前进程ID号)
$0这个程式的执行名字
$n这个程式的第n个参数值,n=1…9
$*这个程式的所有参数,此选项参数可超过9个。
$#这个程式的参数个数
$-显示shell使用的当前选项,与set命令功能相同
$@跟$*类似,但是可以当作数组用
$!执行上一个背景指令的PID(后台运行的最后一个进程的进程ID号)
$?执行上一个指令的返回值 (显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误)
$OSTYPE, $HOSTTYPE, $MACHTYPE操作系统、主机、机器类型

${} $() $的区别

$()和反引号``的作用结果相同都是用来作命令替换的,通俗来讲就是把命令执行后的结果作为参数返回。
${}和$的作用是变量替换, 与 {}与 效果相同,${}中的{}相当于一个界线符,可以很好的划分界限以免混淆
$(())整数运算

变量操作

形式意义
${vat#str}从变量首开始删除,找最短符合删除
${vat##str}从变量首开始删除,找最长符合删除
${vat%str}从变量尾开始删除,找最短符合删除
${vat%%str}从变量尾开始删除,找最长符合删除
${var/oldstr/newstr}找到的第一个被替换
${var//oldstr/newstr}找到的全部被替换
${file: m:n}提取从m处开始的n个字符,首字符为0
var=${str-expr}变量未定义赋值,否则将str赋给var
var=${str:-expr}变量未定义或为空赋值,否则将str赋给var
var=${str+expr}变量若定义则赋值,否则将str赋给var
var=${str:+expr}变量非空赋值,否则将str赋给var
var=${str=expr}若变量str未定义,设定变量str,将值赋给str和var,否则将str赋给var
var=${str:=expr}变量未定义或为空,将值赋给str和var,否则将str赋给var
var=${str?expr}变量不存在报错,否则将str赋给var
var=${str:?expr}变量不存在或为空报错,否则将str赋给var

记忆方法:
#是去掉左边 (在键盘上#在${}的左边)
%是去掉右边(在键盘上%在${}的右边)
单一符号是最小匹配﹔两个符号是最大匹配。

一些有用的管道命令

命令意义
cut使用某种格式从文件中截取每一行中的某一字段
grep利用正则表达式分析一行数据
sort根据制定格式对行排序
uniq去重
wc统计相关字、行、字符数
tee双向重导向,可以重定向输出到文件的同时依旧输出到屏幕
tr文字替换
coltab替换为空格
join归并两个文件中相同的部分
paste将两个文件贴在一起,以tab分隔
expandtab转空格
split分隔文件
xargs参数代换
sed流编辑,可直接编辑文件;添加多行时要以\分隔;替换: sed 's/要被取代的字符串/新的字符串/g'多用于以行为单位的处理
printf格式化打印
awk字段处理
diff比较文件差异
cmp对比文件(以字节为单位)
patch根据diff修订文件
pr显示时加入标题页码

:

  • awk 的指令间隔:所有 awk 的动作,亦即在 {} 内的动作,如果有需要多个指令辅助时,可利用分号;间隔, 或者直接以 [Enter]
    按键来隔开每个指令
  • 逻辑运算当中,如果出现是否等于的情况,则务必使用两个等号==
  • 格式化输出时,在 printf 的格式设定当中,务必加上 \n ,才能进行分行!
  • 与 bash shell 的变量不同,在 awk 当中,变量可以直接使用,不需加上 $ 符号。

脚本编写

test命令 与判断符号 [ ]

注意:判断符号里面都要有两个空格分隔如[空格-e filename空格]
判断符有以下特点:

  1. 在中括号 [] 内的每个组件都需要有空格键来分隔;
  2. 在中括号内的变量,最好都以双引号括号起来;
  3. 在中括号内的常量,最好都以单或双引号括号起来;

条件判断

原型:

 if[ expr1];then
 ...
 elseif[expr2];then
 ...
 elseif[exprn];then
 ...
 else
 ...
 fi

原型

case $var in
	变量内容1)
	...
	;;
	变量内容2)
	...
	;;
	*)
	...
	;;
easc

最后的*)相当于switch里的default

例子:

case "$foo" in ""|"$DMROOT."|"$DMROOT.DeviceInfo."*)
	...
	;;

如上case语句表示若$foo变量的值为空,或者为$DMROOT.或者为$DMROOT.DeviceInfo.xxx(xxx为任意字符),则可以匹配。

循环

原型:

while [ condition ]
do
程序段落
done

until [ condition ]
do
程序段落
done

for var in con1 con2 con3 ...
do
程序段
done 
#作为循环选取,可使用`$(seq 1 100)`或bash内建的{1..100}来完成1
#到100序列,字母也可以如{a..g}

for (( 初始值; 限制值; 执行步阶 ))
do
程序段
done

分号

在Linux bash shell中,语句中的分号一般用作代码块标识
比如

if [ -f requirements.txt ]; then echo ok; fi

if [ -f requirements.txt ]
then echo ok;
fi

效果是一样的。如果你在shell里面按行依次输入命令,然后查看命令历史,看到的也是一行的以分号分割的命令。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值