Shell 基础编程

Shell 基础编程

Shell 变量

如何定义一个变量?

eg:

name="Best Wu"

上面的指令为定义一个变量name 值为 "Best Wu"

命名规则
  • 首个字符必须为字母(a-z,A-Z)
  • 中间不能有空格,可以使用下划线(_)
  • 不能使用标点符号
  • 不能使用 bash 里的关键字(可用 help 命令查看保留关键字)

如何使用变量?

eg:

name="Best Wu"

echo $name
echo ${name}

备注:echo 执行的两个命令,均为输出变量的值,变量名外边的花括号是可选的,加花括号是为了帮助解释器识别变量的边界。

Shell 传递参数

$*$@ 区别
  • 相同点:都是引用所有参数
  • 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,则 $* => 1 2 3 传递一个参数,而 $@ => "1" "2" "3" 传递三个参数

eg:

# !/bin/bash
# author: Best Wu

echo "-- \$* 演示 --"
for i in "$*"; do
	echo $i
done

echo "-- \$@ 演示 --"
for i in "$@"; do
	echo $i
done

执行脚本:

chmod +x test.sh
./test.sh 1 2 3

Shell 数组

语法
arr_name=(value1 value2 ... valuen)

eg:

# !/bin/bash
# author: Best Wu

arr=(A B C D)
获取元素
${arr[index]}

eg:

# !/bin/bash
# author: Best Wu

arr=(A B C D)

echo "${arr[0]}"
echo "${arr[1]}"
echo "${arr[2]}"
echo "${arr[3]}"

eg:

# !/bin/bash
# author: Best Wu

arr[0]=A
arr[1]=B
arr[2]=C
arr[3]=D

echo "all elements: ${arr[*]}"
echo "all elements: ${arr[@]}"

Shell 基本运算符

算术运算符

原生 bash 不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。

expr 是一款表达式计算工具,使用它能完成表达式的求值操作。

例如,两个数相加(注意使用的是反引号`` 而不是单引号'`):

# !/bin/bash
# author: Best Wu

val=`expr 2 + 2`

echo "2+2:=$val"

注意:

  1. 表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2 ,这与我们熟悉的大多数编程语言不一样。
  2. 完整的表达式要被反单引号 ``包含,注意这个字符不是常用的单引号。

关系运算符

eg:

a=10
b=20

if [$a -eq $b]
then
	echo "a = b"
else
	echo "a != b"
fi

布尔运算符

a=10
b=20

if [$a != $b]
then
	echo "a != b"
else
	echo "a = b"
fi

逻辑运算符

if [[ $a -lt 100 && $b -gt 100 ]]
then
	echo "true"
else
	echo "false"
fi	

字符串运算符

a="abc"
b="efg"

if [$a = $b]
then
	echo "a = b"
else
	echo "a != b"
fi	

文件测试运算符

file="/opt/test.sh"
if [-r $file]
then 
	echo "file is readable"
else
	echo "file is unreadable"
fi	

Shell echo 命令

格式
echo string
显示普通字符(双引号可以忽略)
echo "hello world"
echo hello world
显示转义字符
echo "\"hello world\""
echo \"hello world\"
显示变量

read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量:

# !/bin/bash

read name
echo "${name} is a test"

保存 test.sh 接受标准输入的变量,运行结果:

sh test.sh Tom
显示换行

-e 开启转义 ,\n 换行

echo -e "OK! \n"
echo It is a test

输出结果

OK!
It is a test
显示不换行

-e 开启转义,\c 不换行

# !/bin/bash
echo -e "OK! \c"
echo It is a test

输出结果

OK! It is a test
显示结果定向至文件
echo It is a test > filename
原样输出字符串,不进行转义获取变量(用单引号)
echo '$name\"'

输出结果

$name\"
显示命令执行结果
echo `date`

注意:这里使用的是反引号 `,而非单引号。

输出结果显示当前日期:

样例输出:

echo `date`
Mon Sep 21 08:26:01 CST 2020

Shell printf 命令

语法:

printf format-string [arguments...]

参数说明:

  • format-string:为格式控制字符串
  • arguments:为参数列表

示例:

echo "Hello, Shell"

printf "Hello, Shell\n"

展现 printf 的一个强大功能

# !/bin/bash
# author: Best Wu

printf "%-10s %-8s %-4s\n" Name Sex Weight-kg
printf "%-10s %-8s %-4.2f\n" GuoJing male 66.1234
printf "%-10s %-8s %-4.2f\n" YangGuo male 48.6543
printf "%-10s %-8s %-4.2f\n" GuoFu female 47.9876

输出:

# 提权操作
chmod +x ./printf.sh
# 执行
./printf.sh

# 执行结果
Name 		Sex 	Weight-kg
GuoJing		male 	66.12
YangGuo		male	48.65
Guofu		male	47.99

ps:

  • %s %c %d %f 都是格式替代符
  • %-10s 指一个宽度为 10 个字符(- 表示左对齐,没有则表示右对齐),任何字符都会被显示在 10 个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
  • %-4.2f 指格式化为小数,其中 .2 指保留两位小数(带四舍五入)

printf 的转义序列

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

Shell test 命令

Shell 中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。

数值测试

参数说明
-eq等于则为真
-ne不等于则为真
-gt大于则为真
-ge大于等于则为真
-lt小于则为真
-le小于等于则为真

示例:

num1=100
num2=100
if test $[ num1 ] -eq $[ num2 ]
then 
	echo "两个数相等"
else
	echo "两个数不相等"
fi	

代码块中的 [] 执行基本的算术运算:

# !/bin/bash
a=5
b=6

# 注意等号两边不能有空格
result=$[a+b]
echo "result ${result}"

字符串测试

参数说明
=等于则为真
!=不等于则为真
-z 字符串字符串的长度为零则为真
-n 字符串字符串的长度不为零则为真

示例:

num1="ru1noob"
num2="runoob"

if test ${num1} = ${num2}
then
	echo "两个字符串相等"
else
	echo "两个字符串不等"
fi

文件测试

参数说明
-e 文件名如果文件存在则为真
-r 文件名如果文件存在且可读则为真
-w 文件名如果文件存在且可写则为真
-x 文件名如果文件存在且可执行则为真
-s 文件名如果文件存在且至少有一个字符则为真
-d 文件名如果文件存在且为目录则为真
-f 文件名如果文件存在且为普通文件则为真
-c 文件名如果文件存在且为字符型特殊文件则为真
-b 文件名如果文件存在且为块特殊文件则为真

示例:

cd /bin

if test -e ./bash
then 
	echo "文件已存在"
else
	echo "文件不存在"
fi	

shell 还提供了 与(-a)、或(-o)、非(!) 三个逻辑操作符用于将测试条件连接起来,优先级从高到低依次:!, -a, -o

示例:

cd /bin
if test -e ./notFile -o -e ./bash
then 
	echo "有一个文件存在"
else
	echo "两个文件都不存在"
fi	

Shell 流程控制

和 Java、PHP 等语言不一样,sh 的流程控制不可为空。在 bash 脚本中,如果 if 后 else 中没有代码块,那么不要写 else ,直接 fi 结束就好。

if

示例:

a=100
b=100
if test $[ a ] -eq $[ b ]
then 
	echo "a = b"
fi	

适用于终端命令行的写法:

if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi

if else

示例:

a=100
b=100
if test $[ a ] -eq $[ b ]
then 
	echo "a = b"
else 
	echo "a != b"
fi	

if elseif else

示例:

a=100
b=100
if test $[ a ] -eq $[ b ]
then 
	echo "a = b"
elif test $[ a ] -gt $[ b ]
then
	echo "a > b"
else 
	echo "a != b"
fi	
a=10
b=20

if [ $a == $b ]
then 
	echo "a 等于 b"
elif [ $a -gt $b ]
then 
	echo "a 大于 b"
elif [ $a -lb $b ]
then
	echo "a 小于 b"
else
	echo "没有符合的条件"
fi	
	

if else 语句经常与 test 命令结合使用:

num1=$[ 2*3 ]
num2=$[ 1+5 ]

if test $[ num1 ] -eq $[ num2 ]
then
	echo "两个数字相等!"
else
	echo "两个数字不相等"
fi	

for 循环

语法格式:

for var in item1 item2 ... itemN
do
	command1
	...
	commandN
done	

写成一行:

for var in item1 item2 ... itemN; do command1; command2; ... done;

当变量值列表里,for 循环即执行一次所有命令,使用变量名获取列表中的当前值。命令可为任何有效的 shell 命令和语句。in 列表可以包含替换、字符串和文件名。in 列表是可选的,如果不用它,for 循环使用命令行的位置参数。例如,顺序输出当前列表中的数字:

for loop in 1 2 3 4 5
do 
	echo "The value is: ${loop}"
done	

顺序输出字符串中的字符:

for str in 'This is a string'
do
	echo ${str}
done	

while 语句

while 循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件,其格式:

while condition
do 
	command
done	

以下是一个基本的 while 循环,测试条件是:如果 int 小于等于 5 ,那么条件为真。int 从 0 开始,每次循环处理时,int 加 1。运行上述脚本,返回数字 1 到 5,然后终止。

# !/bin/bash
int=1
while(($int <= 5))
do 
	echo $int
	let "int++"
done

使用了 Bash let 命令,它用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。

while 循环可用于读取键盘信息。下面的例子中,输入信息被设置为变量 FILM,按结束循环。

echo '按下 <CTRL-D> 退出'
echo -n "输入你最喜欢的电影名: "
while read FILM
do 
	echo "是的 ! $FILM 是一部好电影"
done	

无限循环

格式:

while :
do
	command
done	
while true
do
	command
done	
for(( ; ; ))

until 循环

until 循环执行一系列命令直至条件为真时人停止。

until 循环与 while 循环在处理方式上刚好相反。

一般 while 循环优于 until 循环,但在某些时候也只是少数情况下,until 循环更加有用。

语法格式:

until condition
do
	command
done	

条件可为任意测试条件,测试发生在循环末尾,因此循环至少执行一次。

case

shell case 语句为多选择语句。可以用 case 语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。

语法格式:

casein
模式1)
	command1
	...
	;;
模式2)
	command1
	...
	;;
esac	

case 工作方式如上所示。取值后面必须为单词 in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至;;

取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用 * 捕获该值,再执行后面的命令。

下面的脚本提示输入 1 到 4,与每一种模式进行匹配:

echo "输入 1 到 4 之间的数字:"
echo "你输入的数字为:"
read anum
case $anum in
	1) echo "你选择了 1"
	;;
	2) echo "你选择了 2"
	;;
	3) echo "你选择了 3"
	;;
	4) echo "你选择了 4"
	;;
	*) echo "你没有选择 1 到 4 之间的数字"
	;;
esac	

跳出循环

在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell 使用两个命令来实现该功能:break 和 continue。

break 命令

break 命令允许跳出所有循环(终止执行后面的所有循环)。

下面的例子中,脚本进入死循环直至用户输入数字大于 5 。要跳出这个循环,返回到 shell 提示符下,需要使用 break 命令。

# !/bin/bash
# author: Best Wu

while :
do 
	echo -n "输入 1 到 5 之间的数字:"
	read num
	case $num in
	1 | 2 | 3 | 4 | 5 ) echo "你输入的数字为 ${num}";;
	*) echo "你输入的数字不是 1 到 5 之间的!游戏结束" 
		break
	;;
    esac
done    
continue 命令

continue 命令与 break 命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。对上面的例子进行修改:

# !/bin/bash
# author: Best Wu

while :
do 
	echo -n "输入 1 到 5 之间的数字:"
	read num
	case $num in
	1 | 2 | 3 | 4 | 5 ) echo "你输入的数字为 ${num}";;
	*) echo "你输入的数字不是 1 到 5 之间的!游戏结束" 
		continue
	;;
    esac
done    

运行代码发现,当输入大于 5 的数字时,该例的循环不会结束。

esac

case 的语法和 C family 语言差别很大,它需要一个 esac (就是 case 反过来)作为结束标记,每个 case 分支用右圆括号,用两个分好表示退出当前分支。

Shell 函数

linux shell 可以用户定义函数,然后在 shell 脚本中可以随便调用。

语法格式:

[ function ] funcName [()]
{
	action;
	[return int;]
}

说明:

  • 可以带 function fun() 定义,也可以直接 fun() 定义,不带任何参数
  • 参数返回,可以显示加 return 返回,若不加,将以最后一条命令运行结果,作为返回值。return 后跟数值 n (0~255)
样例1(无 return)
# !/bin/bash
# author: Best Wu

myFunc() {
	echo "this is my first shell function"
}

echo "----function start----"
myFunc
echo "----function end----"
样例2(有 return)
# !/bin/bash
# author: Best Wu

funWithReturn() {
	echo "Two nums add each other..."
	echo "Input the first num1:"
	read num1
	echo "Input the second num2:"
	read num2
	echo "Two nums are ${num1} and ${num2}"
	return $(($num1+$num2))
}

funWithReturn
echo "num1 + num2 = $?"

函数返回值在调用该函数后通过 $? 来获得。

注意:所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至 shell 解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。

函数参数

在 Shell 中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1 表示第一个参数,$2 表示第二个参数…

样例:
# !/bin/bash
# author: Best Wu

funWithParam() {
	echo "The first param is $1"
	echo "The second parma is $2"
	echo "The tenth param is $10" # 这里注意输出的结果是 10 $1取到了第一个参数值,后边拼接了 0,故输出 10
	echo "The tenth param is ${10}" # 这里匹配的是第十个参数,故输出是 34
	echo "The eleventh param is ${11}"
	echo "Total count is $# " # $# 参数总数量
	echo "A string of all param is $* " # $* 匹配输入的所有参数
}

funWithParam 1 2 3 4 5 6 7 8 9 34 73

注意: $10 不能取到第 10 个参数,获取第 10 个参数需要 ${10}。当 n >= 10 时,需要使用 ${n} 来获取参数。

几个处理参数的特殊字符:
参数处理说明
$#传递到脚本的参数个数
$*以一个单字符串显示所有向脚本传递的参数
$$脚本运行的当前进程 ID 号
$!后台运行的最后一个进程 ID 号
$@与 $* 相同,但是使用时加引号,并在引号中返回每个参数
$-显示 shell 使用的当前选项,与 set 命令功能相同。
$?显示最后命令的退出状态。0 表示没有错误,其他任何值表明有错误。

Shell 输入、输出重定向

大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回到您的终端。一个命令通常从一个叫标准输入的地方读取输入,默认情况下,这恰好是你的终端。同样,一个命令通常将其输出写入到标准输出,默认情况下,这也是你的终端。

命令说明
command > file将输出重定向到 file
command < file将输入重定向到 file
command >> file将输出以追加的方式重定向到 file
n > file将文件描述符为 n 的文件重定向到 file
n >> file将文件描述符为 n 的文件以追加的方式重定向到 file
n >& m将输出文件 m 和 n 合并
n <& m将输入文件 m 和 n 合并
<< tag将开始标记 tag 和结束标记 tag 之间的内容作为输入

ps:需要注意的是文件描述符 0 通常是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)

输出重定向

重定向一般通过在命令间插入特定的符号来实现。特别的,这些符号的语法如下所示:

command > file

上面这个命令执行 command 然后将输出的内容存入 file 文件。注意任何 file 内的已经存在的内容将被新内容替代。如果要将新内容添加在文件末尾,请使用 >> 操作符。

样例

执行下面的 who 命令,它将命令的完整的输出重定向在用户文件中(users):

who > users

执行后,并没有在终端输出信息,这是因为输出已被从默认的标准输出设备(终端)重定向到指定的文件。可以使用 cat 命令查看文件 users 中的内容。

输出重定向会覆盖文件内容:

echo "Hello world" > users
cat users
Hello world

如果不希望文件内容被覆盖,可以使用 >> 追加到文件末尾,例如:

echo "Hello world" >> users
cat users
Hello world
Hello world

输入重定向

和输出重定向一样,UNIX 命令可以从文件获取输入,语法为:

command < file

这样,本来需要从键盘获取输入的命令会转移到文件读取内容。

样例

接着以上实例,我们需要统计 users 文件的行数,执行以下命令:

wc -l users
2 users

也可以将输入重定向到 users 文件:

wc -l < users
2

注意:上面两个例子的结果不同,第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容。

command < infile > outfile

同事替换输入和输出,执行 command 命令,从文件 infile 读取内容,然后将输出写入到 outfile 中。

重定向深入讲解

一般情况下,每个 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。

如果希望 stderr 重定向到 file,可以这样写:

command 2 > file

如果希望 stderr 追加到 file 文件末尾,可以这样写:

command 2 >> file

2表示标准错误文件(stderr)

如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写:

command > file 2>&1

或者

command >> file 2>&1

如果希望对 stdin 和 stdout 都重定向,可以这样写:

command < file1 > file2

command 命令将 stdin 重定向到 file1,将 stdout 重定向到 file2。

Here Document

Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式 Shell 脚本或程序。

它的基本的形式如下:

command << delimiter
	document
delimiter	

它的作用是将两个 delimiter 之间的内容(document)作为输入传递给 command。

注意:1. 结尾的 delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。2. 开始的 delimiter 前后的空格会被忽略掉。

样例

在命令行中通过 wc -l 命令计算 Here Document 的行数:

wc -l << EOF
	Hello
	World
	Tom
EOF
3 # 结果输出为 3 行

我们也可以将 Here Document 用在脚本中,例如:

# !/bin/bash
# author: Best Wu

cat << EOF
	Hello
	World
	Tom
EOF	

执行以上脚本,输出结果:

Hello
World
Tom

/dev/null 文件

如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null :

command > /dev/null

/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到“禁止输出”的效果。

如果屏蔽 stdout 和 stderr,可以这样写:

command > /dev/null 2>&1

Shell 文件包含

和其他语言一样,Shell 也可以包含外部脚本。这样可以很方便的封装一些公用的代码作为一个独立的文件。

Shell 文件包含的语法格式如下:

. filename # 注意(.)和文件名中间有一个空格
# 或者
source filename
样例

创建两个 shell 脚本文件。

# test1.sh
# !/bin/bash
# author: Best Wu

url="http://www.baidu.com"
# test2.sh
# !/bin/bash
# author: Best Wu

# 方法一:使用点号(.)来引用 test1.sh
. ./test1.sh

# 方法二:使用 source 命令
# source ./test1.sh

echo "百度:$url"

运行 test2.sh

sh -x test2.sh
百度:http://www.baidu.com

Bash let 命令

let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。

语法格式:

let arg [arg ...]

参数说明:

arg: 要执行的表达式

样例
# !/bin/bash
# author: Best Wu

let no++
let no--
let no+=10
let no=no+10

let no-=20
let no=no-20

加减运算:

# !/bin/bash
# author: Best Wu

let a=5+4
let b=9-3
echo $a $b

输出 9 6

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值