linux_shell编程

相关文章:

linux小题
客制化linux
linux_shell编程
linux基础

shell

Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。

Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。

#!/bin/bash
echo “Hello World !”

! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。

echo 命令用于向窗口输出文本。

运行 Shell 脚本有两种方法:

1、作为可执行程序
将上面的代码保存为 test.sh,并 cd 到相应目录:
chmod +x ./test.sh #使脚本具有执行权限
./test.sh #执行脚本
注意,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找。

2、作为解释器参数
这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名,如:
/bin/sh test.sh
/bin/php test.php
这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。

这种方法会产生子shell,局部变量

Linux执行Scripts有两种方式,主要区别在于是否建立subshe

  1. source filename or . filename
    不创建subshell,在当前shell环境下读取并执行filename中的命令,相当于顺序执行filename里面的命令

  2. bash filename or ./filename
    创建subshell,在当前bash环境下再新建一个子shell执行filename中的命令
    子shell继承父shell的变量,但子shell不能使用父shell的变量,除非使用export

pstree查看后:

image-20240228192155051

1
2
3
4
5
6
7
8
9
10
11
12
[sunnyli@sunnyli ~]$ echo num=1 > test.sh
[sunnyli@sunnyli ~]$ num=2
[sunnyli@sunnyli ~]$ echo $num
2
[sunnyli@sunnyli ~]$ chmod +x test.sh
[sunnyli@sunnyli ~]$ ./test.sh 创建子shell执行
[sunnyli@sunnyli ~]$ echo $num
2

[sunnyli@sunnyli ~]$ . test.sh 不创建子shell
[sunnyli@sunnyli ~]$ echo $num
1
  • ./test.sh或者bash test.sh 这种方式会启动一个新的子shell来执行 test.sh 脚本。在子shell中执行完脚本后,会返回到原来的shell环境,但是子shell无法修改父shell的变量,所以在父shell中的 num 仍然保持为原来的值。

  • . test.sh 或者 source test.sh 这种方式会在当前shell环境中直接执行 test.sh 脚本,而不会启动一个新的子shell。因此,当脚本中对变量 num 进行赋值时,会影响到当前shell环境中的 num 变量的值,导致父shell中的 num 被修改为脚本中所赋的值。

单双反引号

单引号所见即所得,直接显示单引号里的内容。

双引号则是先把变量解析之后,再输出。

反引号用于命令替换,即先执行反引号中的语句,再把结果加入到原命令中。

内外置命令

内置命令:在系统启动时就加载入内存,常驻内存,执行效率更高,但是占用资源

外置命令:系统需要从硬盘中读取程序文件,再读入内存加载

1
2
3
4
[sunnyli@sunnyli ~]$ type cd
cd 是 shell 内嵌
[sunnyli@sunnyli ~]$ type bash
bash 是 /usr/bin/bash

变量

定义变量
定义变量时,变量名不加美元符号($,PHP语言中变量需要),如:

your_name=”runoob.com”

注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:
命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
中间不能有空格,可以使用下划线 _。
不能使用标点符号。
不能使用bash里的关键字(可用help命令查看保留关键字)。

使用变量
$在Linux shell编程中用于取变量值
使用一个定义过的变量,只要在变量名前面 加$ 即可,如:

your_name=”qinjx”
echo $your_name
echo ${your_name}

${变量} 返回变量值
${注释 #变量} 返回变量长度,字符长度
${变量:start} 返回变量start数值之后的字符,且包含start的数字
${变量:start:length} 提取start之后的length限制的字符,例如${name:4:1)
${变量#word} 从变量开头删除最短匹配的word子串
${变量##word} 从变量开头,删除最长匹配的word
${变量%word} 从变量结尾删除最短的word
${变量//pattern/string} 用string代替所有的pattern
${变量%%word} 从变量结尾开始删除最长匹配的word
${变量/pattern/string} 用string代替第一个的pattern

result=${parameter:-word}

如果parameter变量值为空,返回word字符串,赋值给result变量

result=${parametq:=word}

如果para变量为空,则word替代变量值,且返回其值

${parameter:?word}

如果para变量为空,word当作stderr输出,否则输出变量值用于设置变量为空导致错误时,返回的错误信息

${parameter:+word}

如果para变量为空,什么都不做,否则word返回

变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:

for skill in Ada Coffe Action Java; do
echo “I am good at ${skill}Script”
done

``可以带回指令的返回值,除了显式地直接赋值,还可以用语句给变量赋值,如:

for file in ls /etc

for file in $(ls /etc)

命令行参数
以上语句将 /etc 下目录的文件名循环出来。

$1,$2…${10}获取命令行位置参数
$# 传递到脚本或函数的参数个数
$* 以一个单字符串显示所有向脚本传递的参数
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ 与$相同,但是使用时加引号,并在引号中返回每个参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。*函数返回值在调用该函数后通过$? 来获得。

这几个参数都通过命令行输入

只读变量
使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
下面的例子尝试更改只读变量,结果报错:

#!/bin/bash
myUrl=”https://www.google.com"
readonly myUrl
myUrl=”https://www.baidu.com"

运行脚本,结果如下:

/bin/sh: NAME: This variable is read only.

删除变量
使用 unset 命令可以删除变量。语法:

unset variable_name

变量被删除后不能再次使用。unset 命令不能删除只读变量。

环境变量的加载顺序

image-20240229091149967

输出

printf
和c类似

printf “%d %s\n” 1 “abc”

echo

echo “\“It is a test\“”

运算符

运算符

expr支持模式匹配 expr 1.jpg “:” “.* \ .jpg*”

echo $[5*3]
echo $(((2+3)-3))
echo `expr 3+3`

15
2
3+3

tr

tr只支持单个字符替换

1
2
[sunnyli@sunnyli ~]$ echo {1..10} |tr " " " + " 
1 2 3 4 5 6 7 8 9 10

seq

生成一段序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[sunnyli@sunnyli ~]$ seq  10
1
2
3
4
5
6
7
8
9
10
[sunnyli@sunnyli ~]$ seq 4 10
4
5
6
7
8
9
10
[sunnyli@sunnyli ~]$ seq -s "+" 10
#-s 指定分隔符
1+2+3+4+5+6+7+8+9+10

条件测试

test

-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。
-e 文件名 如果文件存在则为真
-r 文件名 如果文件存在且可读则为真
-w 文件名 如果文件存在且可写则为真
-x 文件名 如果文件存在且可执行则为真
-s 文件名 如果文件存在且至少有一个字符则为真
-d 文件名 如果文件存在且为目录则为真

-z 字符串 判断是否为空

-n 字符串 判断是否有

-f 文件名 如果文件存在且为普通文件则为真
-c 文件名 如果文件存在且为字符型特殊文件则为真
-b 文件名 如果文件存在且为块特殊文件则为真

[]

test和[]的作用是一样注意的点:中括号,前后的空格必须有。

在条件测试中使用变量,必须添加双引号[-n “$filename” ]

image-20240229145034946

image-20240229150524924

流程控制

所有的流程控制[ 条件 ] 条件两侧有空格
if

if condition1
then
command1
elif condition2
then
command2
else
commandN
fi

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

末尾的 fi 就是 if 倒过来拼写,后面还会遇到类似的

case

*case $变量名 in
“值”)
语句
;;
“值”)
语句
;;
)
语句
;;
esac

case $1 in
“1”)
echo “1”
;;
*)
echo ‘…’
;;
esac

for
for循环一般格式为:

for var in item1 item2 … itemN
do
command1
command2

commandN
done

for loop in 1 2 3 4 5
do
echo “The value is: $loop”
done

while

while condition
do
command
done

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

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

函数

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

funWithReturn(){
echo “这个函数会对输入的两个数字进行相加运算…”
echo “输入第一个数字: “
read -p “我是提示信息” aNum
echo “输入第二个数字: “
read anotherNum
echo “两个数字分别为 $aNum 和 $anotherNum !”
return $(($aNum+$anotherNum))
}
funWithReturn
echo “输入的两个数字之和为 $? !”