shell编程之步步为营(2):位置变量、shift、算术运算

本文介绍了Shell编程中的关键概念,包括位置变量、算术运算、条件测试等,并提供了实用示例。

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

我们今天接着学习shell编程!

首先接着介绍shell脚本中的非常重要的一种变量:位置变量


位置变量 : 在脚本中调用通过命令行参数传递给脚本的参数。


$1 , $2 , … : 对应调用第1、第2…等参数
$0 : 命令本身
$* : 传递给脚本的所有参数
$@ : 传递给脚本的所有参数(与$*是有区别的)
$# : 传递给脚本的参数个数

示例:
我们写一个脚本test.sh来测试一下:

#!/bin/bash
#
echo $0
echo $2
echo "\$* : $*"
echo "\$@ : $@"
echo "\$# : $#"

执行命令,结果如下:

[jeffrey@localhost ~]$ chmod +x test.sh
[jeffrey@localhost ~]$ ./test.sh Tom Jerry Cherry
./test.sh
Jerry
$* : Tom Jerry Cherry
$@ : Tom Jerry Cherry
$# : 3

shift : 参数左移


用法
在shell脚本中,用于将参数踢出:
shift :踢出一个参数,即第二个参数变成第一个,第三个参数变成第二个;
shift # :踢出#个参数;

示例:
我们输入4个参数,分别为Tom,Jerry,Cherry,Baby,首先打印出第一个参数,即Tom;然后踢出第一个参数,此时第二个参数Jerry变成第一个参数,再次打印参数1,显示的便是Jerry…

#!/bin/bash
#
echo $1
shift
echo $1
shift 2
echo $1
echo "\$* : $*"
echo "\$@ : $@"
echo "\$# : $#"

[jeffrey@localhost ~]$ ./test.sh Tom Jerry Cherry Baby
Tom
Jerry
Baby
$* : Baby
$@ : Baby
$# : 1

算术运算


执行算术运算操作有如下四种方式:
(1)# let var = EXPRESSION 运算结果不直接打印出来;
(2)# var = $[ EXPRESSION ] 运算结果会直接打印出来;
(3)# var = $(( EXPRESSION )) 运算结果直接打印出来;
(4)# var = $(expr EXPRESSION) 算术表达式以空格隔开,结果不直接打印出来,且*需要转义;

示例1:

[jeffrey@localhost ~]$ num1=4
[jeffrey@localhost ~]$ num2=8

[jeffrey@localhost ~]$ let sum=$num1+$num2
[jeffrey@localhost ~]$ echo $sum
12

示例2:

[jeffrey@localhost ~]$ var1=$[$num1+$num2]
[jeffrey@localhost ~]$ echo $var1
12

示例3:

[jeffrey@localhost ~]$ var2=$(($num1+num2))
[jeffrey@localhost ~]$ echo $var2
12

示例4:注意,表达式变量与运算符要以空格隔开;

[jeffrey@localhost ~]$ var3=$(expr $num1 + $num2)
[jeffrey@localhost ~]$ echo $var3
12

  • bash内建的随机数生成器:$RANDOM

示例:
生产60以内的随机数

[jeffrey@localhost ~]$ VAR=$[$RANDOM%60]
[jeffrey@localhost ~]$ echo $VAR
18
[jeffrey@localhost ~]$ VAR=$[$RANDOM%60]
[jeffrey@localhost ~]$ echo $VAR
48
[jeffrey@localhost ~]$ VAR=$(($RANDOM%60))
[jeffrey@localhost ~]$ echo $VAR
6
[jeffrey@localhost ~]$ let VAR=$RANDOM%60
[jeffrey@localhost ~]$ echo $VAR
49
[jeffrey@localhost ~]$ VAR=$(expr $RANDOM % 60)
[jeffrey@localhost ~]$ echo $VAR
37

  • 增强型赋值

+=,-=,*=,/=,%=,++,–

示例:

[jeffrey@localhost ~]$ let var=13
[jeffrey@localhost ~]$ echo $var
13
[jeffrey@localhost ~]$ let var-=3
[jeffrey@localhost ~]$ echo $var
10
[jeffrey@localhost ~]$ let var*=2
[jeffrey@localhost ~]$ echo $var
20
[jeffrey@localhost ~]$ let var/=4
[jeffrey@localhost ~]$ echo $var
5
[jeffrey@localhost ~]$ let var%=3
[jeffrey@localhost ~]$ echo $var
2
[jeffrey@localhost ~]$ let var++
[jeffrey@localhost ~]$ echo $var
3
[jeffrey@localhost ~]$ let var--
[jeffrey@localhost ~]$ echo $var
2

条件测试:判断条件是否满足;由测试机制来实现;


用法
专用的测试表达式需要由测试命令辅助完成测试过程,测试命令如下:

~]# test EXPRESSION
~]# [ EXPRESSION ]
~]# [[ EXPRESSION ]]

注:EXPRESSION前后必须有空格,并且[ ]或[[ ]]中的变量和运算符要以空格分隔;

bash的测试类型: 数值测试 、字符串测试、文件测试。

数值测试

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

示例1:

[jeffrey@localhost ~]$ test 1>3
[jeffrey@localhost ~]$ echo $?
1

示例2:

[jeffrey@localhost ~]$ [ 100 -eq 100 ]
[jeffrey@localhost ~]$ echo $?
0

示例3:

[jeffrey@localhost ~]$ [[ 100 -ne 100 ]]
[jeffrey@localhost ~]$ echo $?
1

字符串测试:用于字符串比较时的操作数应该加引号

  • ==或者= 相等
  • > 大于
  • < 小于
  • != 不等于
  • =~ 左侧是否能被右侧的PATTERN匹配,一般用于[[ ]]中;
  • -z “STRING” 测试字符串是否为空;不空为真、空为假;
  • -n “STRING” 测试字符串是否不为空;不空为真、空为假;

示例1:

[jeffrey@localhost ~]$ name=jeffrey
[jeffrey@localhost ~]$ echo $name
jeffrey

/*下面错误的原因是[和-z之间没以空格隔开*/
[jeffrey@localhost ~]$ [-z "$name"]
bash: [-z: command not found...

jeffrey@localhost ~]$ [ -z "$name" ]
[jeffrey@localhost ~]$ echo $?
1

示例2:

[jeffrey@localhost ~]$ myname=jeffrey
[jeffrey@localhost ~]$ [ -n "$myname" ]
[jeffrey@localhost ~]$ echo $?
0

示例3:

[jeffrey@localhost ~]$ [ "$name" = "$myname" ]
[jeffrey@localhost ~]$ echo $?
0

示例4:

jeffrey@localhost ~]$ [[ "$name" =~ ^m ]]
[jeffrey@localhost ~]$ echo $?
1
[jeffrey@localhost ~]$ [[ "$name" =~ ^t ]]
[jeffrey@localhost ~]$ echo $?
1

文件测试

(1)文件存在性测试

  • -a FILE 及 -e FILE 测试文件是否存在;

(2)存在性及类别测试

  • -b FILE 文件是否存在且为快文件
  • -c FILE 文件是否存在且为字符设备文件
  • -d FILE 文件是否存在且为目录文件
  • -f FILE 文件是否存在且为普通文件
  • -p FILE 文件是否存在且为命名管道文件
  • -S FILE 文件是否存在切勿套接字文件
  • -h FILE 或 -L FILE 文件是否村咋且为符号链接文件

(3)文件权限测试

  • -r FILE 文件是否存在且可读(对于当前用户而言)
  • -w FILE 文件是否存在且可写
  • -x FILE 文件是否存在且可执行

(4)文件特殊权限测试

  • -g FILE 文件是否存在且拥有sgid权限
  • -u FILE 文件是否存在且拥有suid权限
  • -k FILE 文件是否存在且拥有sticky权限

(5)文件大小测试

  • -s FILE 文件是否存在且非空

(6)文件是否打开测试

  • -t fd fd表示文件描述符是否已经打开且与某终端相关

(7)其他测试

  • -N FILE 文件自动上一次被读取之后是否被修改过
  • -O FILE 当前有效用户是否为文件属主
  • -G FILE 当前有效用户是否为文件属组

(8)双目测试

  • FILE1 -ef FILE2 测试FILE1和FILE2是否指向同一设备上的相同inode
  • FILE1 -nt FILE2 测试FILE1是否新于FILE2
  • FILE1 -ot FILE2 测试FILE1是否旧于FILE2

基于以上几种测试类型,我们将其组合起来进行组合测试:

组合测试
在进行组合测试时,我们需要进行逻辑的运算,即与、或、非,与之前说过的条件测试命令结合起来,有以下两种形式;

形式1:

  • && 与
  • || 或
  • !非

形式2:

  • -o 与
  • -a 或
  • !非

那么,我们的组合测试方式也相应地有两种方式;

方式1:
[ EXPRESSION1 ] && [ EXPRESSION2 ]
[ EXPRESSION1 ] | | [ EXPRESSION2 ]
! [ EXPRESSION ] 或 [ ! EXPRESSION ]

方式2:
[ EXPRESSION1 -a EXPRESSION2 ]
[ EXPRESSION1 -a EXPRESSION2 ]
! [ EXPRESSION ] 或 [ ! EXPRESSION ]

我们常用的测试命令为[ ],当然也可以是其他测试命令;

我们示例说明:
首先,我们查看/usr/bin/ls和/work的详细信息;
/usr/bin/ls为普通文件,属主权限为可读可写可执行;
/work为目录文件,属主权限为可读可写可执行;

[jeffrey@localhost ~]$ ls -l /usr/bin/ls && ls -l -d /work
-rwxr-xr-x. 1 root root 117672 Apr 10 21:35 /usr/bin/ls
drwxr-xr-t. 4 root root 51 Sep 10 04:17 /work

1,我们测试“/usr/bin/ls存在 且 /work要对于当前用户root可读”,结果应为正确;

法一:

[root@localhost jeffrey]# [ -e /usr/bin/ls ] && [ -r /work ]
[root@localhost jeffrey]# echo $?
0

法二:

[root@localhost jeffrey]# [ -e /usr/bin/ls -a -r /work ]
[root@localhost jeffrey]# echo $?
0

2,测试“/usr/bin/ls是目录 且 /work对于当前用户root可读”,其结果应为错误;

法一:

[root@localhost jeffrey]# [ -d /usr/bin/ls ] && [ -r /work ]
[root@localhost jeffrey]# echo $?
1

法二:

[root@localhost jeffrey]# [ -d /usr/bin/ls -a -r /work ]
[root@localhost jeffrey]# echo $?
1

3,测试“/usr/bin/ls是目录 或 /work对于当前用户root可读”,其结果应为正确;

法一:

root@localhost jeffrey]# [ -d /usr/bin/ls ] || [ -r /work ]
[root@localhost jeffrey]# echo $?
0

法二:

[root@localhost jeffrey]# [ -d /usr/bin/ls -o -r /work ]
[root@localhost jeffrey]# echo $?
0

bash自定义退出状态码


bash可以自定义退出状态码:exit n

若脚本中一旦遇到exit命令,脚本会立即终止,终止退出状态取决于exit命令后面的数字;如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码。

今天的练习

1,计算系统上/etc/passwd上第10个用户和第20个用户的ID之和;
脚本sumid.sh内容如下:

#!/bin/bash
#
id1=$(head -10 /etc/passwd | tail -1 | cut -d: -f3)
id2=$(head -20 /etc/passwd | tail -1 | cut -d: -f3)
sum_ID=$[$id1+$id2]
echo "The sum of No.10 id  and No.20 id is $sum_ID"

执行结果如下:

[jeffrey@localhost ~]$ chmod +x sumid.sh
[jeffrey@localhost ~]$ ./sumid.sh
The sum of No.10 id  and No.20 id is 70

2,计算/etc/rc.d/rc.sysinit以及/etc/rc.d传递两个文件路径作为参数给脚本,计算文件的空白行数之和;
脚本blankline.sh内容如下:

#!/bin/bash
#
line1=$(grep "^[[:space:]]*$" $1 | wc -l)
line2=$(grep "^[[:space:]]*$" $2 | wc -l)
sum=$[ $line1 + $line2 ]
echo "blank lines all is $sum"

执行结果:

[root@localhost jeffrey]# ./blankline.sh /etc/profile /etc/bashrc
blank lines all is 18

3,统计/etc,/var,/usr共有多少个子目录和文件;
脚本count.sh内容:

#!/bin/bash
#
num1=$(ls -l /etc | wc -l)
num2=$(ls -l /var | wc -l)
num3=$(ls -l /usr | wc -l)
num=$[$num1+$num2+$num3]
echo "file number is $num"

执行结果如下:

[root@localhost jeffrey]# chmod +x count.sh
[root@localhost jeffrey]# ./count.sh
file number is 333

4,写一个脚本,接受一个文件路径作为参数,若参数行小于1,则提示用户“至少给出一个参数”,并立即退出;否则,显示第一个参数所指向的文件中的空白行数;

脚本test.sh内容:

#!/bin/bash
#
[ "$#" -lt 1 ] && echo "至少应输入一个参数" && exit 125
line=$(grep "^[[:space:]]*$" $1 | wc -l)
echo "$line"

执行结果:

[root@localhost jeffrey]# chmod +x test.sh
[root@localhost jeffrey]# ./test.sh
至少应输入一个参数
[root@localhost jeffrey]# ./test.sh /etc/profile
11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值