r123@localhost:~$ first_var=aaa
r123@localhost:~$ echo $first_var
aaa
r123@localhost:~$ second_var=123
r123@localhost:~$ echo $second_var
123
r123@localhost:~$ third="bbb ccc"
r123@localhost:~$ echo $third
bbb ccc
$
r123@localhost:~$ first_var=123
r123@localhost:~$ first_var=${first_var}456
r123@localhost:~$ echo $first_var
123456
r123@localhost:~$ first_var="$first_var"789
r123@localhost:~$ echo $first_var
123456789
直接使用set
命令将输出目前shell中存在的变量,包括环境变量,我这里以grep
筛选出来自定义变量(通常情况下没有办法选出所有自定义变量)
r123@localhost:~$ set | grep first_var
first_var=123456789
r123@localhost:~$ unset first_var
r123@localhost:~$ echo $first_var
#! /bin/bash
read -p "Input a ipaddress: " ip_address
ping -c 1 ${ip_address} &> /dev/null && echo "${ip_address} Up" || echo "${ip_address} Down"
echo success
""
表示对内部内容进行弱引用,只对空格等字符进行转义,$
等不受影响''
表示对内部内容进行强引用,对$
等也进行转义``
表示更高的执行优先级r123@localhost:~$ first_var=123
r123@localhost:~$ echo "$first_var"456
123456
r123@localhost:~$ first_var=123
r123@localhost:~$ echo '$first_var'456
$first_var456
r123@localhost:~$ echo `ls`456
MyMainClass.java content.txt456
r123@localhost:~$ expr 1 + 1
2
r123@localhost:~$ var_1=123
r123@localhost:~$ var_2=123
r123@localhost:~$ expr $var_1 + $var_2
246
使用expr
时,作为运算两个值或变量必须与运算符有空格隔开,还有以下三种方式进行运算
r123@localhost:~$ echo $(($var_1 + $var_2))
246
r123@localhost:~$ echo $((2 ** 2))
4
r123@localhost:~$ echo $[1+2]
3
r123@localhost:~$ let sum=$var_1+$var_2
r123@localhost:~$ echo $sum
246
r123@localhost:~$ let sum++; echo $sum
247
一般浮点运算需要借助bc
计算器程序
r123@localhost:~$ sudo apt install bc
r123@localhost:~$ echo "2^4" | bc
16
r123@localhost:~$ echo "scale=3; 2/4" | bc
.500
r123@localhost:~$ echo "scale=3; 5/4" | bc
1.250
r123@localhost:~$ echo "scale=2; 5/4" | bc
1.25
环境变量是操作系统中的一种配置参数,用于存储系统和应用程序的配置信息。它们是在操作系统运行时由操作系统或用户设置的键值对。这些键值对包含了一些重要的信息,例如系统路径、临时文件夹位置、语言设置等。在计算机程序中,环境变量通常用于指定应用程序的运行时行为,例如定义特定的路径、设置默认值或启用某些功能。程序可以在运行时读取这些环境变量的值,以便适应不同的运行环境或用户需求
通常我们使用export设置临时环境变量用来达到跨shell
使用目的,即在当前shell中开启一个子shell
后,可以在子shell
中使用该变量,我们可以使用pstree
来展示shell的层级关系,使用exit来退出当前shell
:
r123@localhost:~$ export Base_var=233
r123@localhost:~$ ps | grep bash
40 pts/0 00:00:00 bash
r123@localhost:~$ bash
r123@localhost:~$ bash
r123@localhost:~$ bash
r123@localhost:~$ ps | grep bash
40 pts/0 00:00:00 bash
60 pts/0 00:00:00 bash
67 pts/0 00:00:00 bash
73 pts/0 00:00:00 bash
r123@localhost:~$ pstree
init─┬─init───init───bash───bash───bash───bash───pstree
└─{init}
r123@localhost:~$ exit
exit
r123@localhost:~$ pstree
init─┬─init───init───bash───bash───bash───pstree
└─{init}
r123@localhost:~$ echo $Base_var
233
如果想要设置的变量永久可用,可以添加到环境变量文件,以下是常见表格:
文件 | 加载时机 | 说明 |
---|---|---|
/etc/environment | 系统启动时 | 全局环境变量,对所有用户生效 |
/etc/profile | 用户登录时 | 全局配置文件,对所有用户生效 |
/etc/bash.bashrc | 用户登录时(bash shell) | 全局bash配置文件,对所有用户生效 |
~/.bashrc | 用户登录时(bash shell) | 用户级别的bash配置文件,只对当前用户生效 |
~/.bash_profile | 用户登录时(bash shell) | 用户级别的bash配置文件,仅在用户登录时执行一次 |
~/.profile | 用户登录时 | 用户级别的配置文件,通常由sh、bash、ksh等解释执行 |
~/.zshrc | 用户登录时(zsh shell) | 用户级别的zsh配置文件,只对当前用户生效 |
/etc/profile.d/ | 用户登录时(bash shell) | 目录包含由管理员提供的额外配置文件,以扩展/etc/profile |
~/.config/environment.d/ | 用户登录时 | 目录包含用户特定的环境变量配置文件,以扩展~/.profile |
查看当前shell
加载的的环境变量内容:
r123@localhost:~$ env
SHELL=/bin/bash
WSL_DISTRO_NAME=Ubuntu
...
修改环境变量,这里以当前用户环境变量配置为例:
r123@localhost:~$ vim .profile
...
fi
export myself_var=2333
...
:wq
r123@localhost:~$ source .profile
r123@localhost:~$ echo $myself_var
2333
预定义变量是在Shell脚本中由Shell环境提前定义好的一些特殊变量,用于存储系统信息、脚本运行时的状态等。这些变量在脚本执行期间自动设置,可以用于获取有关执行环境的信息或控制脚本的行为(其中$1
到$9
也称为位置变量):
变量 | 含义 | 示例 |
---|---|---|
$0 | 脚本或命令本身的名称 | 如果脚本名为 myscript.sh ,则 $0 是 myscript.sh |
$1 , $2 , … | 传递给脚本或命令的位置参数,9之后的需要特殊定义 | $1 表示第一个参数,$2 表示第二个参数,以此类推 |
$# | 传递给脚本或命令的位置参数的总数,或变量的长度${#变量} | 如果有三个参数,$# 是 3 |
$* | 所有位置参数的单个字符串 | 如果有参数为 arg1 和 arg2 ,$* 是 arg1 arg2 |
$@ | 所有位置参数的列表,每个参数作为一个单独的词 | 如果有参数为 arg1 和 arg2 ,$@ 是 arg1 和 arg2 |
$? | 上一个命令的退出状态(返回值),0是成功,非0即为失败 | echo $? 可以用于获取上一个命令的退出状态 |
$$ | 当前Shell进程的进程ID | echo $$ 显示当前Shell的进程ID |
$! | 后台运行的上一个命令的进程ID | 在后台运行的命令结束后,$! 包含其进程ID |
$USER | 当前用户的用户名 | echo $USER 显示当前登录用户的用户名 |
$HOME | 当前用户的主目录路径 | echo $HOME 显示当前用户的主目录路径 |
$SHELL | 当前用户使用的Shell | echo $SHELL 显示当前用户使用的Shell |
$PATH | Shell查找可执行文件的路径列表 | echo $PATH 显示Shell查找可执行文件的路径列表 |
在书写脚本时,我们可以做出以下的效果
ping -c 1 $1 &> /dev/null && echo "${1} is Up" || echo "${1} is Down"
echo success
r123@localhost:~$ vim ping.sh
r123@localhost:~$ bash ping.sh 192.168.179.11
192.168.179.11 is Down
success
注意:条件测试不支持浮点值
操作符 | 描述 | 用法 |
---|---|---|
-eq | 等于(equal to) | [ "$a" -eq "$b" ] |
-ne | 不等于(not equal to) | [ "$a" -ne "$b" ] |
-lt | 小于(less than) | [ "$a" -lt "$b" ] |
-le | 小于等于(less than or equal to) | [ "$a" -le "$b" ] |
-gt | 大于(greater than) | [ "$a" -gt "$b" ] |
-ge | 大于等于(greater than or equal to) | [ "$a" -ge "$b" ] |
如果想要直接使用上述比较,需要通过 $?
来获取运算结果:
r123@localhost:~$ [ 20 -gt 10 ]; echo $?
0
r123@localhost:~$ [ 20 -gt 30 ]; echo $?
1
r123@localhost:~$ [ 20-gt30 ]; echo $?
0
需要注意的是,这里的[]
运算符需要与运算内容有空格,否则运算将无法识别
指令 | 描述 | 用法 |
---|---|---|
-e 文件路径 | 检查文件或目录是否存在 | [ -e "$文件路径" ] |
-f 文件路径 | 检查文件是否为普通文件 | [ -f "$文件路径" ] |
-d 文件路径 | 检查文件是否为目录 | [ -d "$文件路径" ] |
-s 文件路径 | 检查文件是否存在且大小不为零 | [ -s "$文件路径" ] |
-r 文件路径 | 检查文件是否可读 | [ -r "$文件路径" ] |
-w 文件路径 | 检查文件是否可写 | [ -w "$文件路径" ] |
-x 文件路径 | 检查文件是否可执行 | [ -x "$文件路径" ] |
-L 文件路径 | 检查文件是否为符号链接 | [ -L "$文件路径" ] |
-b 文件路径 | 检查文件是否为块设备文件 | [ -b "$文件路径" ] |
-g 文件路径 | 检查文件是否具有设置了 SGID 位 | [ -g "$文件路径" ] |
文件类型表格:
文件类型 | 符号 | 说明 |
---|---|---|
普通文件 | - | 包含文本、二进制数据等,没有特殊属性。 |
目录 | d | 包含其他文件和目录的容器。 |
符号链接 | l | 指向另一个文件或目录的链接。 |
块设备文件 | b | 提供对设备的带缓冲的访问,如硬盘分区。 |
字符设备文件 | c | 提供对设备的不带缓冲的访问,如串口。 |
套接字文件 | s | 用于进程间通信的特殊文件。 |
管道文件 | p | 用于进程间通信的命名管道。 |
使用示例:
r123@localhost:~$ ll
total 44
drwxr-x--- 2 r123 r123 4096 Jan 20 00:13 ./
drwxr-xr-x 3 root root 4096 Jan 16 01:32 ../
-rw------- 1 r123 r123 3116 Jan 20 10:44 .bash_history
-rw-r--r-- 1 r123 r123 220 Jan 16 01:32 .bash_logout
-rw-r--r-- 1 r123 r123 3771 Jan 16 01:32 .bashrc
-rw------- 1 r123 r123 20 Jan 20 00:13 .lesshst
-rw-r--r-- 1 r123 r123 0 Jan 20 10:43 .motd_shown
-rw-r--r-- 1 r123 r123 807 Jan 19 15:34 .profile
-rw-r--r-- 1 r123 r123 0 Jan 19 14:47 .sudo_as_admin_successful
-rw------- 1 r123 r123 1444 Jan 19 15:44 .viminfo
-rw-r--r-- 1 r123 r123 127 Jan 17 22:52 MyMainClass.java
-rw-r--r-- 1 r123 r123 152 Jan 17 20:37 content.txt
-rw-r--r-- 1 r123 r123 83 Jan 19 15:44 ping.sh
r123@localhost:~$ [ -f MyMainClass.java ]; echo $?
0
r123@localhost:~$ [ -e MyMainClass.java ]; echo $?
0
r123@localhost:~$ [ -x MyMainClass.java ]; echo $?
1
r123@localhost:~$ [ -g MyMainClass.java ]; echo $?
1
r123@localhost:~$ sudo chmod g+s MyMainClass.java
r123@localhost:~$ [ -g MyMainClass.java ]; echo $?
0
r123@localhost:~$ [ "aaa" = "aaa" ]; echo $?
0
-z
判断字符串长度是0r123@localhost:~$ [ -z "233" ]; echo $?
1
r123@localhost:~$ [ -z "" ]; echo $?
0
r123@localhost:~$ [ -n "233" ]; echo $?
0
r123@localhost:~$ [ -n "" ]; echo $?
1
注意:当比较不存在变量时会出现以下情况
r123@localhost:~$ first_var=233 r123@localhost:~$ unset first_var r123@localhost:~$ echo $first_var r123@localhost:~$ [ -z $first_var ]; echo $? 0 r123@localhost:~$ [ -n $first_var ]; echo $? 0 r123@localhost:~$ echo $first_var
r123@localhost:~$ [ 22 -gt 23 -a 23 -gt 22 ]; echo $?
1
r123@localhost:~$ [[ 22 -gt 23 && 23 -gt 22 ]]; echo $?
1
r123@localhost:~$ [ 22 -gt 23 ] && [ 23 -gt 22 ]; echo $?
1
r123@localhost:~$ [ 22 -gt 23 -o 23 -gt 22 ]; echo $?
0
r123@localhost:~$ [[ 22 -gt 23 || 23 -gt 22 ]]; echo $?
0
r123@localhost:~$ [ 22 -gt 23 ] || [ 23 -gt 22 ]; echo $?
0
利用linux的通配符来进行匹配条件
r123@localhost:~$ [[ 2 = [0-9] ]]; echo $?
0
r123@localhost:~$ [[ 20 = [0-9] ]]; echo $?
1
使用~
表示进行正则匹配
r123@localhost:~$ [[ 20 =~ [0-9] ]]; echo $?
0
r123@localhost:~$ [[ a =~ [0-9] ]]; echo $?
1
r123@localhost:~$ [[ 1 =~ ^[0-9]$ ]]; echo $?
0
r123@localhost:~$ [[ 20 =~ ^[0-9]$ ]]; echo $?
1
r123@localhost:~$ [[ 2 =~ ^[0-9]$ ]]; echo $?
0
Hello World
#!/bin/bash
if [ 2 -gt 1 ]; then
echo "Hello World";
fi
r123@localhost:~$ cat if_test.sh
#!/bin/bash
read -p "Please enter a username: " username
id $username &> /dev/null
if [ $? -eq 0 ]; then
echo "The username is exist"
fi
r123@localhost:~$ bash if_test.sh
Please enter a username: r123
The username is exist
r123@localhost:~$ cat if_test.sh
#!/bin/bash
read -p "Please enter a username: " username
id $username &> /dev/null
if [ $? -eq 0 ]
then
echo "The username is exist"
else
echo "The username is not exist"
fi
r123@localhost:~$ bash if_test.sh
Please enter a username: r123
The username is exist
r123@localhost:~$ bash if_test.sh
Please enter a username: aaa
The username is not exist
这里使用了$?
来避免了直接将命令作为条件传入if
语句,也可以直接将命令作为条件
#!/bin/bash
read -p "Please enter a time of only hour: " user_input_hour
if [ $user_input_hour -gt 24 -o $user_input_hour -lt 0 ];
then
echo "Please enter a correct time"
elif [ $user_input_hour -le 12 ]
then
echo "It's ${user_input_hour} o'clock in the morning"
elif [ $user_input_hour -gt 12 ]
then
echo "It's ${user_input_hour} o'clock in the afternoon"
else
echo "Failed test"
fi
使用
bash -vx 脚本名
可以进行调试脚本r123@localhost:~$ bash -vx elif_test.sh #!/bin/bash read -p "Please enter a time of only hour: " user_input_hour + read -p 'Please enter a time of only hour: ' user_input_hour Please enter a time of only hour: 12 if [ $user_input_hour -gt 24 -o $user_input_hour -lt 0 ]; then echo "Please enter a correct time" ... elif [ $user_input_hour -gt 12 ] then echo "It's ${user_input_hour} o'clock in the afternoon" else echo "Failed test" fi + '[' 12 -gt 24 -o 12 -lt 0 ']' + '[' 12 -le 12 ']' + echo 'It'\''s 12 o'\''clock in the morning' It's 12 o'clock in the morning
在每一句要执行的语句处,将依次输出:原语句、进行操作(以+开头)、执行结果
read -p "Please enter a number from 0 to 9 or a letter: " user_input_value
case $user_input_value in
[0-9])
echo "This is a number which in 1-9"
;;
[a-zA-Z])
echo "This is a letter"
;;
*)
echo "no"
;;
esac
匹配模式为模式匹配,并不能直接使用正则表达式,在每个模式匹配完成后需要使用两个分号,借助以上基础知识,我们可以写一个略微复杂的脚本
#!/bin/bash
web1=192.168.179.2
web2=192.168.179.3
web3=192.168.179.144
web4=192.168.179.145
web5=192.168.179.200
cat <<EOF
1.Web Server 1 ${web1}
2.Web Server 2 ${web2}
3.Web Server 3 ${web3}
4.Web Server 4 ${web4}
5.Web Server 5 ${web5}
EOF
read -p "Please select a Web Server serial number: " select_res
case $select_res in
1)
select_res=$web1
;;
2)
select_res=$web2
;;
3)
select_res=$web3
;;
4)
select_res=$web4
;;
5)
select_res=$web5
;;
esac
echo "The selected host to connect to is Web Server: "$select_res
ping -c 1 $select_res &> /dev/null && echo "${select_res} Up" || echo "${select_res} Down"
echo "Execution is completed"