前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >shell编程基础

shell编程基础

原创
作者头像
墨紫羽墨
修改2022-06-10 18:12:37
7450
修改2022-06-10 18:12:37
举报
文章被收录于专栏:FutureTesterFutureTester

shell命令

shell定义

  • Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。
  • Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

注:

  • shell脚本文件运行需要使用Linux系统
  • 在Linux中创建shell文件可以使用:vi 文件名.sh
  • 运行文件之前需要给文件授权:chmod +x ./文件名.sh
  • 运行文件:./文件名.sh

创建shell脚本文件

在创建shell脚本文件时,必须在文件的第一行指定要使用的shell。其格式为:

代码语言:shell
复制
#!/bin/bash

在通常的shell脚本中,井号(#)用作注释行。shell并不会处理shell脚本中的注释行。但是,shell脚本文件的第一行是个例外,#后面的惊叹号会告诉shell用哪个shell来运行脚本。

第一个脚本:

代码语言:shell
复制
#!/bin/bash
echo "hello, shell"

让shell找到你写的文件,有两种方式:

1) 将shell脚本文件所处的目录添加到PATH环境变量中;

2) 在提示符中用绝对或相对文件路径来引用shell脚本文件。

想运行脚本,还需要有执行此文件的权限,可以用 ls -l 文件名 查看权限,然后使用 chmod +x 文件名 赋予文件被执行的权限。下面就可以在文件所在的目录下用 ./文件名 来执行文件了。

变量

  • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
  • 中间不能有空格,可以使用下划线 _。
  • 不能使用标点符号。
  • 不能使用bash里的关键字(可用help命令查看保留关键字)。
代码语言:shell
复制
#!/bin/bash
num=123
echo "$num"
echo "${num}"
  • 只读变量:使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
代码语言:shell
复制
#!/bin/bash
url="www.baidu.com"
readonly url
str="qwer"
unset str
  • 删除变量:变量被删除后不能再次使用。unset 命令不能删除只读变量
运行shell时,会同时存在三种变量:

1) 局部变量 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。

2) 环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。

3) shell变量 shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行。

字符串

单引号:
  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
双引号:
  • 双引号里可以有变量
代码语言:shell
复制
#!/bin/bash
str="\"qwer\"" # 转义字符
echo `$str`
echo $str
echo -e "this is a string! \n" # -e 开启转义
echo -e "this is a test \c string" # -e 开启转义,\c 不换行
string="abcdefg"
echo ${#string} # 获取字符串长度
echo ${#string0} # 获取字符串长度
echo ${string:1:4} # 截取字符串
echo `expr index "$string" ce` # 查找字符 c 或 e 的位置(哪个字母先出现就计算哪个)
echo `date`
  • 双引号里可以出现转义字符

传递参数

  • 在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……

参数处理

说明

$#

传递到脚本的参数个数

$*

以一个单字符串显示所有向脚本传递的参数。如"\$*"用「"」括起来的情况、以"\$1 \$2 … $n"的形式输出所有参数。

$$

脚本运行的当前进程ID号

$!

后台运行的最后一个进程的ID号

$@

与\$*相同,但是使用时加引号,并在引号中返回每个参数。如"\$@"用「"」括起来的情况、以"\$1" "\$2" … "\$n" 的形式输出所有参数。

$-

显示Shell使用的当前选项,与set命令功能相同。

$?

显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

代码语言:shell
复制
#!/bin/bash
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "传递到脚本的参数个数:$#"
echo "以字符串显示所有参数:$*"
echo "显示所有参数:$@"

数组

  • 数组中可以存放多个值。Bash Shell 只支持一维数组(不支持多维数组)。
代码语言:shell
复制
#!/bin/bash
my_array=(A,b,"C",D)
my_array[4]="E"
echo "第一个元素:${my_array[0]}"
echo "第二个元素:${my_array[1]}"
echo "数组的所有元素:${my_array[*]}"
echo "数组的所有元素:${my_array[@]}"
echo "数组的长度:${#my_array[*]}"
echo "数组的长度:${#my_array[@]}"

运算符

  • 算数运算符

运算符

说明

举例

+

加法

\ expr $a + $b\ | | |

-

减法

expr $a - $b

\*

乘法

expr $a \\* $b

/

除法

expr $b / $a

%

取余

expr $b % $a

=

赋值

a=$b 把变量 b 的值赋给 a。

==

相等。用于比较两个数字,相同则返回 true。

$a == $b 返回 false。

!=

不相等。用于比较两个数字,不相同则返回 true。

$a != $b 返回 true。

代码语言:shell
复制
#!/bin/bash
a=10
b=20
add=`expr $a + $b`
subtract=`expr $b - $a`
mul=`expr $b \* $a`
division=`expr $b / $a`
remainder=`expr $b % $a`
echo "$b和$a 两个数 相加:$add,相减:$subtract,相乘:$mul,相除:$division,取余:$remainder"
  • 关系运算符

运算符

说明

举例

-eq

检测两个数是否相等,相等返回 true。

\$a -eq \$b

-ne

检测两个数是否不相等,不相等返回 true。

\$a -ne \$b

-gt

检测左边的数是否大于右边的,如果是,则返回 true。

\$a -gt \$b

-lt

检测左边的数是否小于右边的,如果是,则返回 true。

\$a -lt \$b

-ge

检测左边的数是否大于等于右边的,如果是,则返回 true。

\$a -ge \$b

-le

检测左边的数是否小于等于右边的,如果是,则返回 true。

\$a -le \$b

代码语言:shell
复制
#!/bin/bash
a=10
b=20
if [ $a -eq $b ]
then
   echo "$a -eq $b : a 等于 b"
else
   echo "$a -eq $b: a 不等于 b"
fi
if [ $a -ne $b ]
then
   echo "$a -ne $b: a 不等于 b"
else
   echo "$a -ne $b : a 等于 b"
fi
if [ $a -gt $b ]
then
   echo "$a -gt $b: a 大于 b"
else
   echo "$a -gt $b: a 不大于 b"
fi
if [ $a -lt $b ]
then
   echo "$a -lt $b: a 小于 b"
else
   echo "$a -lt $b: a 不小于 b"
fi
if [ $a -ge $b ]
then
   echo "$a -ge $b: a 大于或等于 b"
else
   echo "$a -ge $b: a 小于 b"
fi
if [ $a -le $b ]
then
   echo "$a -le $b: a 小于或等于 b"
else
   echo "$a -le $b: a 大于 b"
fi
  • 布尔运算符

运算符

说明

举例

!

非运算,表达式为 true 则返回 false,否则返回 true。

! false

-o

或运算,有一个表达式为 true 则返回 true。

\$a -lt 20 -o \$b -gt 100

-a

与运算,两个表达式都为 true 才返回 true。

\$a -lt 20 -a \$b -gt 100

代码语言:shell
复制
#!/bin/bash
a=10
b=20
if [ $a != $b ]
then
   echo "$a != $b : a 不等于 b"
else
   echo "$a == $b: a 等于 b"
fi
if [ $a -lt 100 -a $b -gt 15 ]
then
   echo "$a 小于 100 且 $b 大于 15 : 返回 true"
else
   echo "$a 小于 100 且 $b 大于 15 : 返回 false"
fi
if [ $a -lt 100 -o $b -gt 100 ]
then
   echo "$a 小于 100 或 $b 大于 100 : 返回 true"
else
   echo "$a 小于 100 或 $b 大于 100 : 返回 false"
fi
if [ $a -lt 5 -o $b -gt 100 ]
then
   echo "$a 小于 5 或 $b 大于 100 : 返回 true"
else
   echo "$a 小于 5 或 $b 大于 100 : 返回 false"
fi
  • 逻辑运算符

运算符

说明

举例

&&

逻辑的 AND

\$a -lt 100 && \$b -gt 100

||

逻辑的 OR

\$a -lt 100 || \$b -gt 100

代码语言:shell
复制
#!/bin/bash
a=10
b=20
if [[ $a -lt 100 && $b -gt 100 ]]
then
   echo "返回 true"
else
   echo "返回 false"
fi

if [[ $a -lt 100 || $b -gt 100 ]]
then
   echo "返回 true"
else
   echo "返回 false"
fi
  • 字符串运算符

运算符

说明

举例

=

检测两个字符串是否相等,相等返回 true。

\$a = \$b

!=

检测两个字符串是否不相等,不相等返回 true。

\$a != \$b

-z

检测字符串长度是否为0,为0返回 true。

-z \$a

-n

检测字符串长度是否不为 0,不为 0 返回 true。

-n "\$a"

$

检测字符串是否为空,不为空返回 true。

\$a

代码语言:shell
复制
#!/bin/bash
a="abc"
b="efg"
if [ $a = $b ]
then
   echo "$a = $b : a 等于 b"
else
   echo "$a = $b: a 不等于 b"
fi
if [ $a != $b ]
then
   echo "$a != $b : a 不等于 b"
else
   echo "$a != $b: a 等于 b"
fi
if [ -z $a ]
then
   echo "-z $a : 字符串长度为 0"
else
   echo "-z $a : 字符串长度不为 0"
fi
if [ -n "$a" ]
then
   echo "-n $a : 字符串长度不为 0"
else
   echo "-n $a : 字符串长度为 0"
fi
if [ $a ]
then
   echo "$a : 字符串不为空"
else
   echo "$a : 字符串为空"
fi
  • 文件测试运算符

操作符

说明

举例

-b file

检测文件是否是块设备文件,如果是,则返回 true。

-b \$file

-c file

检测文件是否是字符设备文件,如果是,则返回 true。

-c \$file

-d file

检测文件是否是目录,如果是,则返回 true。

-d \$file 返回 false。

-f file

检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。

-f \$file

-g file

检测文件是否设置了 SGID 位,如果是,则返回 true。

-g \$file

-k file

检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。

-k \$file

-p file

检测文件是否是有名管道,如果是,则返回 true。

-p \$file

-u file

检测文件是否设置了 SUID 位,如果是,则返回 true。

-u \$file

-r file

检测文件是否可读,如果是,则返回 true。

-r \$file

-w file

检测文件是否可写,如果是,则返回 true。

-w \$file

-x file

检测文件是否可执行,如果是,则返回 true。

-x \$file

-s file

检测文件是否为空(文件大小是否大于0),不为空返回 true。

-s \$file

-e file

检测文件(包括目录)是否存在,如果是,则返回 true。

-e \$file

代码语言:shell
复制
#!/bin/bash
file="/var/www/runoob/test.sh"
if [ -r $file ]
then
   echo "文件可读"
else
   echo "文件不可读"
fi
if [ -w $file ]
then
   echo "文件可写"
else
   echo "文件不可写"
fi
if [ -x $file ]
then
   echo "文件可执行"
else
   echo "文件不可执行"
fi
if [ -f $file ]
then
   echo "文件为普通文件"
else
   echo "文件为特殊文件"
fi
if [ -d $file ]
then
   echo "文件是个目录"
else
   echo "文件不是个目录"
fi
if [ -s $file ]
then
   echo "文件不为空"
else
   echo "文件为空"
fi
if [ -e $file ]
then
   echo "文件存在"
else
   echo "文件不存在"
fi

printf命令

  • 转义字符

序列

说明

\a

警告字符,通常为ASCII的BEL字符

\b

后退

\c

抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略

\f

换页(formfeed)

\n

换行

\r

回车(Carriage return)

\t

水平制表符

\v

垂直制表符

\

一个字面上的反斜杠字符

\ddd

表示1到3位数八进制值的字符。仅在格式字符串中有效

\0ddd

表示1到3位的八进制值字符

代码语言:shell
复制
#!/bin/bash

# format-string为双引号
printf "%d %s\n" 1 "abc"

# 单引号与双引号效果一样
printf '%d %s\n' 1 "abc"

# 没有引号也可以输出
printf %s abcdef

# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用
printf %s abc def

printf "%s\n" abc def

printf "%s %s %s\n" a b c d e f g h i j

# 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替
printf "%s and %d \n"

流程控制

  • if else 流程控制
代码语言:shell
复制
#!/bin/bash
a=10
b=20
if  $a == $b 
then
   echo "a 等于 b"
elif  $a -gt $b 
then
   echo "a 大于 b"
elif  $a -lt $b 
then
   echo "a 小于 b"
else
   echo "没有符合的条件"
fi
# if else 语句经常与 test 命令结合使用
if test $a -eq $b
then
   echo '两个数字相等!'
else
   echo '两个数字不相等!'
fi
  • for循环
代码语言:shell
复制
#!/bin/bash
for loop in 1 2 3 4 5
do
    echo "The value is: $loop"
done
  • while 语句
代码语言:shell
复制
#!/bin/bash
int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"
done
  • until循环
代码语言:shell
复制
#!/bin/bash
a=0
until  ! $a -lt 10 
do
   echo $a
   a=`expr $a + 1`
done
  • case...esac 流程控制
代码语言:shell
复制
#!/bin/sh
site="runoob"
case "$site" in
   "runoob") echo "菜鸟教程"
   ;;
   "google") echo "Google 搜索"
   ;;
   "taobao") echo "淘宝网"
   ;;
esac

函数

创建函数

函数创建有两种格式,第一种格式采用关键字function,后跟分配给该代码块的函数名。第二种格式是函数名后跟空括号。

代码语言:shell
复制
#!/bin/bash
# 格式一
function name { 
 commands 
}
# 格式二
name() { 
commands 
}
使用函数

使用函数,只需要在shell文本中指定需要使用的函数名就行了,但一定要在使用之前先定义函数,然后才能在使用的时候找到这个函数。

代码语言:shell
复制
#!/bin/bash
funWithReturn(){
    echo "这个函数会对输入的两个数字进行相加运算..."
    echo "输入第一个数字: "
    read aNum
    echo "第二个数字: $1"
    echo "两个数字分别为 $aNum 和 $1 !"
    return $(($aNum+$1))
}
funWithReturn 5
echo "输入的两个数字之和为 $? !"
返回值
  • 默认退出状态码

默认情况下,函数的退出状态码是函数中最后一条命令返回的退出状态码。在函数执行结束后,可以用标准变量\$?来确定函数的退出状态码。

代码语言:shell
复制
#!/bin/bash  
func1() { 
 echo "trying to display a non-existent file" 
 ls -l badfile 
} 
echo "testing the function: " 
func1 
echo "The exit status is: $?"

因为函数中的最后一条命令没有成功运行。无法知道函数中其他命令中是否成功运行。

代码语言:shell
复制
#!/bin/bash  
func1() { 
 echo "trying to display a non-existent file" 
 ls -l badfile
 echo "This was a test of a bad command"
} 
echo "testing the function: " 
func1 
echo "The exit status is: $?"

这个函数最后一条语句echo运行成功,该函数的退出状态码就是0,尽管其中有一条命令并没有正常运行。

  • 使用return命令

bash shell使用return命令来退出函数并返回特定的退出状态码。

代码语言:shell
复制
#!/bin/bash 
# using the return command in a function 
function dbl { 
 read -p "Enter a value: " value 
 echo "doubling the value" 
 return $[ $value * 2 ] 
} 
dbl 
echo "The new value is $?" 
代码语言:txt
复制
  记住,函数一结束就取返回值;
代码语言:txt
复制
  记住,退出状态码必须是0~255。

如果在用\$?变量提取函数返回值之前执行了其他命令,函数的返回值就会丢失。记住,\$?变量会返回执行的最后一条命令的退出状态码。

第二个问题界定了返回值的取值范围。由于退出状态码必须小于256,函数的结果必须生成一个小于256的整数值。任何大于256的值都会产生一个错误值。

  • 使用函数输出
代码语言:shell
复制
#!/bin/bash 
# using the echo to return a value 
function dbl { 
 read -p "Enter a value: " value 
 echo $[ $value * 2 ] 
} 
result=$(dbl) 
echo "The new value is $result" 

函数会用echo语句来显示计算的结果。该脚本会获取dbl函数的输出,而不是查看退出状态码。

在函数中使用变量

函数可以使用标准的参数环境变量来表示命令行上传给函数的参数。例如,函数名会在\$0变量中定义,函数命令行上的任何参数都会通过\$1、\$2等定义。也可以用特殊变量\$#来判断传给函数的参数数目。

代码语言:shell
复制
#!/bin/bash 
function addem { 
 if [ $# -eq 0 ] || [ $# -gt 2 ] 
 then 
   echo -1 
 elif [ $# -eq 1 ] 
 then 
   echo $[ $1 + $1 ] 
 else 
   echo $[ $1 + $2 ] 
 fi 
} 
echo -n "Adding 10 and 15: " 
value=$(addem 10 15) 
echo $value 
echo -n "Let's try adding just one number: " 
value=$(addem 10) 
echo $value 
echo -n "Now trying adding no numbers: " 
value=$(addem) 
echo $value 
echo -n "Finally, try adding three numbers: " 
value=$(addem 10 15 20) 
echo $value
代码语言:shell
复制
#!/bin/bash 
# trying to access script parameters inside a function 
function func7 { 
 echo $[ $1 * $2 ] 
} 
if [ $# -eq 2 ] 
then 
 value=$(func7 $1 $2) 
 echo "The result is $value" 
else 
 echo "Usage: badtest1 a b" 
fi

通过将\$1和\$2变量传给函数,它们就能跟其他变量一样供函数使用了。

在函数中处理变量
  • 全局变量:在shell脚本中任何地方都有效的变量。默认情况下,你在脚本中定义的任何变量都是全局变量。
  • 局部变量:无需在函数中使用全局变量,函数内部使用的任何变量都可以被声明成局部变量。只要在变量声明的前面加上local关键字就可以了。
代码语言:shell
复制
#!/bin/bash 
function func1 { 
 local temp=$[ $value + 5 ] # 不影响外部全局变量
 result=$[ $temp * 2 ] 
} 
temp=4 
value=6 
func1 
echo "The result is $result" 
if [ $temp -gt $value ] 
then 
 echo "temp is larger" 
else 
 echo "temp is smaller" 
fi
向函数传数组参数
代码语言:shell
复制
#!/bin/bash 
function testit {    
 local newarray 
 newarray=(;'echo "$@"') 
 echo "The new array value is: ${newarray[*]}" 
} 
myarray=(1 2 3 4 5) 
echo "The original array is ${myarray[*]}" 
testit ${myarray[*]}

该脚本用\$myarray变量来保存所有的数组元素,然后将它们都放在函数的命令行上。该函数随后从命令行参数中重建数组变量。在函数内部,数组仍然可以像其他数组一样使用。

从函数返回数组
代码语言:shell
复制
#!/bin/bash 
function arraydblr { 
 local origarray 
 local newarray 
 local elements 
 local i 
 origarray=($(echo "$@")) 
 newarray=($(echo "$@")) 
 elements=$[ $# - 1 ] 
 for (( i = 0; i <= $elements; i++ )) 
 { 
 newarray[$i]=$[ ${origarray[$i]} * 2 ] 
 } 
 echo ${newarray[*]} 
} 
myarray=(1 2 3 4 5) 
echo "The original array is: ${myarray[*]}" 
arg1=$(echo ${myarray[*]}) 
result=($(arraydblr $arg1)) 
echo "The new array is: ${result[*]}"

该脚本用\$arg1变量将数组值传给arraydblr函数。arraydblr函数将该数组重组到新的数组变量中,生成该输出数组变量的一个副本。然后对数据元素进行遍历,将每个元素值翻倍,并将结果存入函数中该数组变量的副本。

arraydblr函数使用echo语句来输出每个数组元素的值。脚本用arraydblr函数的输出来重新生成一个新的数组变量。

函数递归
代码语言:shell
复制
#!/bin/bash 
function factorial { 
 if [ $1 -eq 1 ] 
   then 
   echo 1 
 else 
   local temp=$[ $1 - 1 ] 
   local result=$(factorial $temp) 
   echo $[ $result * $1 ] 
 fi 
}
read -p "Enter value: " value 
result=$(factorial $value) 
echo "The factorial of $value is: $result" 
文件包含

当一个函数需要重复使用时,可以单独写入一个文件。

创建两个shell脚本文件

test1.sh

代码语言:shell
复制
#!/bin/bash
url="http://www.runoob.com"
function addem { 
 echo $[ $1 + $2 ] 
}

test2.sh

代码语言:shell
复制
#!/bin/bash
#使用 . 号来引用test1.sh 文件
. ./test1.sh # 被包含的文件 test1.sh 不需要可执行权限。

# 或者使用以下包含文件代码
# source ./test1.sh

echo "菜鸟教程官网地址:$url"
result=$(addem 10 15) 
echo "The result is $result"

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • shell命令
    • shell定义
      • 创建shell脚本文件
      • 变量
      • 字符串
      • 传递参数
      • 数组
      • 运算符
      • printf命令
      • 流程控制
      • 函数
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档