【shell脚本编程大全-笔录01】

环境变量

全局、局部环境变量

​ 用户变量(局部变量):修改的设置只对某个用户的路径或执行起作用;
​ 系统变量(全局变量):影响范围是整个系统 ;

系统环境变量基本上都是使用全大写字母,以区别于普通用户的环境变量。

查看

# 查看全局变量
$ env
$ printenv
$ printenv HOME	# 要显示个别环境变量的值,可以使用printenv命令,但是不能用env命令

# 查看当前环境变量,set命令会显示某个特定进程设置的所有环境变量,包括局部变量、全局变量以及用户定义变量
$ set

env、printenv和set之间的差异:
1、set命令会显示出全局变量、局部变量以及用户定义变量。它还会按照字母顺序对结果进行排序。
2、env和printenv命令不会对变量排序,也不会输出局部变量和用户定义变量。在这种情况下,env和printenv的输出是重复的。不过env命令有一个printenv没有的功能,这使得它要更有用一些。

设置变量

# 设置局部变量
$ my_variable= "Hello World"

# 设置全局变量,可以通过export命令使局部变量变成全局变量
$ export my_variable

# 删除环境变量
$ unset my_variable

注意:如果在子进程中删除了一个全局环境变量, 这只对子进程有效。该全局环境变量在父进程中依然可用。

设置 PATH

$ PATH=$PATH:/home/xx/xx

​ 对PATH变量的修改只能持续到退出或重启系统。这种效果并不能一直持续。

环境变量持久化

​ 当登录Linux系统时,bash shell会作为登录shell启动。登录shell会从5个不同的启动文件里读取命令:

  • /etc/profile
  • $HOME/.bash_profile
  • $HOME/.bashrc
  • $HOME/.bash_login
  • $HOME/.profile

​ /etc/profile文件是系统上默认的bash shell的主启动文件。系统上的每个用户登录时都会执行这个启动文件。另外4个启动文件是针对用户的,可根据个人需求定制。

​ 1、对全局环境变量来说,可能更倾向于将新的或修改过的变量设置放在**/etc/profile**文件中,但这可不是什么好主意。如果你升级了所用的发行版,这个文件也会跟着更新,那你所有定制过的变量设置可就都没有了。

​ 2、最好是在**/etc/profile.d目录中创建一个以.sh结尾的文件**。把所有新的或修改过的全局环境变量设置放在这个文件中。

​ 3、在大多数发行版中,存储个人用户永久性bash shell变量的地方是** H O M E / . b a s h r c ∗ ∗ 文件。这一点适用于所有类型的 s h e l l 进程。但如果设置了 ∗ ∗ B A S H E N V ∗ ∗ 变量,那么除非它指向的是 ∗ ∗ HOME/.bashrc**文件。这一点适用于所有类型的shell进程。但如果设置了**BASH_ENV**变量,那么除非它指向的是** HOME/.bashrc文件。这一点适用于所有类型的shell进程。但如果设置了BASHENV变量,那么除非它指向的是HOME/.bashrc**,否则你应该将非交互式shell的用户变量放在别的地方。

​ alias命令设置就是不能持久的,可以把alias设置放在 $HOME/.bashrc 启动文件中,使其效果永久化。

数组

​ 要给某个环境变量设置多个值,可以把值放在括号里,值与值之间用空格分隔。

$ mytest=(one two three four five)
$ echo ${mytest[0]}
one
$ echo ${mytest[1]}
two
$ echo ${mytest[*]} 
one two three four five
#改变某个索引值位置的值
$ mytest[2]=seven
$ echo ${mytest[*]} 
one two seven four five
#删除
$ unset mytest[2]      //这里只是删除了值,[2]变成空了而已
$ unset mytest

数学运算

expr 命令

​ expr命令允许在命令行 上处理数学表达式,但需要转义特殊字符。

#!/bin/bash 
var1=10 
var2=20 
var3=$(expr $var2 / $var1) 
echo The result is $var3

使用方括号 [ ]

​ 不需要转义特殊字符,但只支持整数运算

#!/bin/bash 
var1=100 
var2=50 
var3=45 
var4=$[$var1 * ($var2 - $var3)] 
echo The final result is $var4

内建计算器:bc

​ bash计算器能够识别:整数和浮点数、变量、注释、表达式、编程语句、函数

#!/bin/bash 
var1=100 
var2=45 
var3=$(echo "scale=4; $var1 / $var2" | bc)	# scale:小数位数,默认0
echo The answer for this is $var3
如果需要进行大量运算,EOF字符串标识了重定向给bc命令的数据的起止
#!/bin/bash 
var1=10.46 
var2=43.67 
var3=33.2 
var4=71 

var5=$(bc << EOF 
scale = 4 
a1 = ( $var1 * $var2) 
b1 = ($var3 * $var4) 
a1 + b1 
EOF 
)
echo $var5

退出状态码

查看退出状态

$?

Linux退出状态码:

状态码 描述
0 执行成功
1 一般性未知错误(参数有误)
2 不适合的shell命令
126 命令不可执行(无权限)
127 没有找到命令
128 无效的退出参数
128+x 与Linux信号x相关的严重错误
130 通过Ctrl+c终止的命令
255 正常范围之外的退出状态码

自定义退出状态码

​ 默认情况下,shell脚本会以脚本中的最后一个命令的退出状态码退出。
exit 命令允许在脚本结束时指定一个退出状态码。例如:

$ cat test13 
#!/bin/bash 
# testing the exit status 
var1=10 
var2=30 
var3=$[$var1 + $var2] 
echo The answer is $var3 
exit 5 # 指定退出状态码
# exit var2	# 可以指定变量

$ chmod u+x test13 
$ ./test13 
The answer is 40 
$ echo $? 
5 

注意:退出状态码最大只能是255,区间为:0~255

字段分隔符 IFS

IFS环境变量定义了bash shell用作字段分隔符的一系列字符。
​ 默认情况下,bash shell会将下列字符当作字段分隔符: 空格、制表符、换行符如果bash shell在数据中看到了这些字符中的任意一个,它就会假定这表明了列表中一个新数据字段的开始。
​ 可以将IFS的值也可以设为其他,也可以设置多个:

# 将IFS的值设为冒号(:)
IFS=: 
# 设置多个,将换行符($'\n')、冒号(:)、分号(;)和双引号(")作为字段分隔符
IFS=$'\n':;"
#!/bin/bash 
# reading values from a file 
file="states" 
# 设置字段分割为换行符
IFS=$'\n' 
for f in $(cat $file) 
do 
 echo "Visit beautiful $f" 
done 

​ 在处理代码量较大的脚本时,可能在一个地方需要修改IFS的值,然后忽略这次修改,在脚本的其他地方继续沿用IFS的默认值。一个可参考的安全实践是在改变IFS之前保存原 来的IFS值,之后再恢复它。 这种技术可以这样实现:

IFS.OLD=$IFS  
IFS=$'\n'  
[代码...] 
IFS=$IFS.OLD

​ 这就保证了在脚本的后续操作中使用的是IFS的默认值。

判断条件

test 命令

​ 如果test命令中列出的条件成立,test命令就会退出并返回退出状态码0
​ test命令可以判断三类条件:数值比较、字符串比较、文件比较

if test condition
then 
 commands
fi

[ ] 替代test命令

​ [ ] 定义测试条件,等同 test 命令。

if [ condition ] # condition 前后需要加一个空格
then 
 commands
fi

数值比较

  • -eq 等于
  • -ne 不等
  • -gt 大于
  • -ge 大于等于
  • -lt 小于
  • -le 小于等于

bash shell只能处理整数,不支持浮点值比较。

字符串比较

  • str1 = str2 检查str1是否和str2相同
  • str1 != str 检查str1是否和str2不同
  • str1 < str2 检查str1是否比str2小
  • str1 > str2 检查str1是否比str2大
  • -n str1 检查str1的长度是否不为0
  • -z str1 检查str1的长度是否为0

字符串比较大小时,有两个问题:
1、大于号和小于号必须转义,否则shell会把它们当作重定向符号,把字符串值当作文件名;
2、大于和小于顺序和sort命令所采用的不同,顺序相反;

空的和未初始化的变量也可以用-n、-z判断。

文件比较

  • -d file 检查file是否存在,且是否为目录
  • -f file 检查file是否存在,且是否为文件
  • -e file 检查file目录或文件是否存在
  • -r file 检查file目录或文件是否存在,并可读
  • -s file 检查file目录或文件是否存在,并非空
  • -w file 检查file目录或文件是否存在,并可写
  • -x file 检查file目录或文件是否存在,并可执行
  • -O file 检查file目录或文件是否存在,并属当前用户所有
  • -G file 检查file目录或文件是否存在,并且默认组与当前用户相同
  • file1 -nt file2 检查file1是否比file2新
  • file1 -ot file2 检查file1是否比file2旧

布尔运算( && 、|| )

  • A && B 当A命令执行成功,才执行B
  • A || B 仅当A执行失败,才执行B

布尔逻辑是一种能够将可能的返回值简化为TRUE或FALSE的方法。

[ A && B ] 使用AND布尔运算符来组合两个条件。两个条件都必须满足,then部分的命令才会执行。
[ A || B ] 使用OR布尔运算符来组合两个条件。任意条件为TRUE,then部分的命令就会执行。

双括号 (( ))

​ 双括号命令允许你在比较过程中使用高级数学表达式。 只能进行整数运算,不能对小数(浮点数)或者字符串进行运算。

(( expression ))	# expression 可以是任意的数学赋值或比较表达式
  • 表达式可以有多个,多个表达式之间以逗号,分隔。对于多个表达式的情况,以最后一个表达式的值作为整个 (( )) 命令的执行结果: echo $((a=3+5, b=a+10)) 输出:15 ;
  • 可以使用 $ 获取 (( )) 命令的结果,这和使用 获得变量值类似: a = 获得变量值类似:a= 获得变量值类似:a=((10+66);
  • 在 (( )) 内使用变量无需加上 前缀,会自动解析变量名: ( ( a + b ) ) ,但要获取结果时需要加上 c = ∗ ∗ 前缀,会自动解析变量名:((a+b)),但要获取结果时需要加上c=** 前缀,会自动解析变量名:((a+b)),但要获取结果时需要加上c=**((a+b));

除了支持简单的加减乘除外,还支持其他运算符:

符合 描述
val++ 后增
val– 后减
++val 先增
–val 先减
! 逻辑求反
~ 位求反
** 幂运算
<< 左位移
>> 右位移
& 位布尔和
| 位布尔或
&& 逻辑和
|| 逻辑或

​ 可以在 if 语句中用双括号命令,也可以在脚本中的普通命令里使用来赋值:

$ cat test.sh
#!/bin/bash 

val1=10 
if (( $val1 ** 2 > 90 )) ; then
 (( val2 = $val1 ** 2 )) 
 echo "The square of $val1 is $val2" 
fi 

$ ./test.sh
The square of 10 is 100

注意:不需要将双括号中表达式里的大于号转义。这是双括号命令提供的另一个高级特性。

双方括号 [[ ]]

​ 双方括号命令提供了针对字符串比较的高级特性

[[ expression ]]

​ 双方括号里的expression使用了test命令中采用的标准字符串比较。但它提供了test命 令未提供的另一个特性(模式匹配)。在模式匹配中,双方括号中可以定义一些正则表达式来匹配字符串:

$ cat test.sh
#!/bin/bash 

if [[ $USER == r* ]] 
then 
 echo "Hello $USER" 
else 
 echo "Sorry, I do not know you" 
fi 

$ ./test.sh
Hello rich 

注意:不是所有的shell都支持双方括号!

小数比较

$ echo "1.8 < 1.6" |bc	# 不成立输出 0
0
$ echo "1.8 > 1.6" |bc	# 成立输出 1
1
#!/bin/bash

a=0.23
b=0.9

if [ $(echo "$a > $b" | bc) = 1 ]; then
 echo "a>b"
else
 echo "a<b"
fi

结构化命令

if-then

​ 与其他编程语言不同,shell 的 if 语句会运行 if 后面的命令,如果该命令的退出状态码是0 (该命令成功运行),位于then部分的命令就会被执行。如果该命令的退出状态码是其他值就不会被执行,会继续执行脚本中的下一个命令。

if command ; then
	commands
elif command ; then
	commands
else
	commands
fi

$ cat test1.sh
#!/bin/bash 
# testing the if statement 
if pwd 
then 
 echo "It worked" 
fi

# 这个脚本在if行采用了pwd命令。如果命令成功结束,再执行echo语句
$ ./test1.sh
/home/Christine 
It worked 

case 命令

​ case命令:为变量每个可能的值指定不同的选项。

case variable in 
 pattern1 | pattern2) commands1;; 
 pattern3) commands2;; 
 *) default commands;; 
esac

​ case 匹配不同的某值,如果匹配成功则执行它下面的命令,直到 ;; 为止

#!/bin/bash 
echo '输入 1 到 3 之间的数字:'
echo '你输入的数字为:'
read Num
case $Num in
	1) echo '你选择了 1' ;;	# 2|3) 值内容可以加上|可以有多个值
	2) echo '你选择了 2' ;;
	3) echo '你选择了 3' ;;
	*) echo '你没有输入 1 到 3 之间的数字' ;;	# 如以上都不匹配,则执行这条
esac			#结束
	echo "test case end"	#输出内容

for 循环

#!/bin/bash 
list="A B C D"
list=$list" E"	# 这是向变量中存储的已有文本字符串尾部添加文本的一个常用方法
for test in $list
do 
	echo The next number is $test 
done
echo The last number is $test	# for结束后,test变量会一直保持最后一次迭代的值

# 从命令读取值遍历
#!/bin/bash 
file="test.txt" 
for f in $(cat $file) 
do 
 echo "Visit beautiful $f" 
done 

​ for命令默认用空格、制表符、换行符来划分列表中的每个值。如果在单独的数据值中有空格,就必须用双引号将这些值圈起来。

​ 也可以将do语句和for语句放在同一行,但必须用分号将其同列表中的值分开:for var in list; do

用通配符遍历目录
# 遍历目录文件,支持多个目录
for file in /home/rich/.b* /home/rich/badtest/*
do 
 if [ -d "$file" ]	# 将$file变量用双引号圈起来,预防有带空格的目录
 then 
   echo "$file is a directory" 
 elif [ -f "$file" ] 
 then 
   echo "$file is a file" 
 else 
   echo "$file doesn't exist" 
 fi 
done 

​ 在Linux中,目录名和文件名中包含空格当然是合法的。要适应这种情况,应该将$file变量用双引号圈起来。如果不这么做,遇到含有空格的目录名或文件名时就会有错误产生:
​ ./test6: line 6: [: too many arguments

for迭代( i++ )

#!/bin/bash 
for (( i=1; i <= 10; i++ )) 
do 
 echo "The next number is $i" 
done

$ ./test8 
The next number is 1 
The next number is 2 
...

# 可以使用多个变量
#!/bin/bash 
# multiple variables 
for (( a=1, b=10; a <= 10; a++, b-- )) 
do 
 echo "$a - $b" 
done 

while 循环

​ while命令允许定义一个要测试的命令(条件),只要定义的测试命令返回非0退出状态码时,while命令会停止循环。

​ while命令允许你在while语句行定义多个测试命令只有最后一个测试命令不成立时停止循环。

#!/bin/bash 
var1=10 
while echo $var1 
 [ $var1 -ge 0 ] 	# 注意:每个测试命令都在单独的一行上
do 
 echo "This is inside the loop" 
 var1=$[ $var1 - 1 ] 
done 

until 循环

until命令和while命令工作的方式完全相反。until命令要求你指定一个通常返回非零退出状态码的测试命令。只有测试命令的退出状态码不为0,bash shell才会执行循环中列出的命令。 一旦测试命令返回了退出状态码0,循环就结束了。

​ 和while命令类似,可以指定的多个测试命令,只有在最后一个测试命令成立时停止循环

#!/bin/bash 
var1=100 
until echo $var1 
 [ $var1 -eq 0 ] 
do 
 echo Inside the loop: $var1 
 var1=$[ $var1 - 25 ] 
done 

循环处理文件数据

​ 通过修改IFS环境变量,就能强制for命令将文件中的每行都当成单独的一个条目来处理,即便数据中有空格也是如此。一旦从文件中提取出了单独的行,可能需要再次利用循环来提取行中的数据。

#!/bin/bash 
# 遍历/etc/passwd文件中的数据
IFS=$'\n'
for entry in $(cat /etc/passwd) 
do 
 echo "Values in $entry –" # 先换行符间隔遍历
 IFS=:
 	for
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeStarNote

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值