该篇文章为摘抄,是对原作者系列文章的总汇加上标注。
linux shell 脚本 入门到实战详解[⭐建议收藏!!⭐]_linux shell脚本_宝山的博客的博客-CSDN博客
如何在 Linux 中创建并运行 Shell 脚本(Bash 初学者教程)_linux shell脚本_BugMiaowu2021的博客-CSDN博客
Linux学习笔记09 -- 超详细shell脚本编程快速入门_Freedom_Bule的博客-CSDN博客
一、如何在linux中创建并运行shell脚本
1、创建并运行第一个 shell 脚本
首先创建一个名为 scripts 的新目录,它将托管我们所有的 bash 脚本。
mkdir scripts
cd scripts
现在在这个“脚本目录”中,使用 cat 命令创建一个名为 hello.sh的新文件:
cat > hello.sh
通过在终端中键入以下内容,在其中插入以下行:
echo 'Hello, World!'
按 Ctrl+D 将文本保存到文件中,同时从 cat 命令中出来。
你还可以使用基于终端的文本编辑器,如 Vim、Emacs或 Nano。如果你使用的是桌面 Linux,还可以使用图形文本编辑器(如 Gedit)将文本添加到此文件中。
基本上你是在使用echo 命令来打印“Hello World”。你可以直接在终端中使用此命令,但在本测试中,你将通过 shell 脚本运行此命令。
现在使用 chmod 命令使文件 hello.sh 可执行,如下所示:
chmod u+x hello.sh

最后,通过在 hello.sh 前面加上“bash”来运行你的第一个 shell 脚本:
bash hello.sh
你就会看到Hello, World!打印在屏幕上。
[root@localhost scripts]# bash hello.sh
Hello, World!
2、将 shell 脚本转换为 bash 脚本
Bash是“Bourne-Again shell”的缩写,它只是 Linux 中许多可用 shell 的一种。
shell 是一个命令行解释器,它接受并运行命令。如果你以前运行过任何 Linux 命令,那么你已经使用过 shell。当你在 Linux 中打开终端时,你已经在运行系统的默认 shell。
Bash 通常是大多数 Linux 发行版中的默认 shell。这就是为什么 bash 通常是 shell 的同义词。Shell 只是一个程序,而 bash 是它的一个实现。还有其他这样的 shell 程序,如 ksh、zsh等。如果你安装了其他 shell,你也可以使用它来代替 bash。
shell 脚本通常具有几乎相同的语法,但有时也会有所不同。例如,数组索引在 Zsh 中从 1 开始,而不是在 bash 中从 0 开始。如果为Zsh shell编写的脚本有数组,则它在 bash 中将无法正常工作。
为了避免这种错误,你应该告诉解释器你的 shell 脚本是为 bash shell 编写的。你是怎样做的?你可以用shebang来实现这一点。
3、为什么大多数 shell 脚本都包含 #! /bin/bash 在 shell 脚本的开头?
“#!/bin/bash”这一行被称为shebang 行,在某些文献中,它被称为hashbang 行,这是因为它以两个字符hash '#' 和bang '!' 开头。
#! /bin/bash
echo 'Hello, World!'
当你在脚本的最顶部包含“#!/bin/bash”行时,系统知道你想使用 bash 作为脚本的解释器。因此,你现在可以直接运行 hello.sh 脚本,而无需在其前面加上 bash。
使用 #!/bin/bash 表示该脚本是 bash shell 脚本,无论系统上正在使用什么 shell,都应该使用 bash 作为解释器运行。如果你使用的是 zsh 特定的语法,你可以通过添加 #! /bin/zsh 作为脚本的第一行。
#! 和 /bin/bash 之间的空格无关紧要。你也可以使用 #!/bin/bash。
4、将 shell 脚本添加到 PATH(以便它可以从任何目录运行)
前面使用 ./hello.sh 来运行脚本;如果省略前导 ./
在这里插入图片描述Bash 认为你正在尝试运行名为 hello.sh 的命令。当你在终端上运行任何命令时,shell 就在存储在 PATH 变量中的一组目录中查找该命令。
可以使用 echo 查看该 PATH 变量的内容:echo $PATH
在这里插入图片描述冒号字符 (:) 分隔每次运行命令时 shell 扫描的每个目录的路径。
像 echo、cat 等 Linux 命令可以从任何地方运行,因为它们的可执行文件存储在 bin 目录中。bin 目录包含在 PATH 中。当你运行命令时,系统会检查 PATH 以查找它应该寻找的所有可能位置,以找到该命令的可执行文件。
如果你想从任何地方运行你的 bash 脚本,就像它是一个常规的 Linux 命令,需要将你的 shell 脚本的位置添加到 PATH 变量中。
首先,获取脚本目录的位置(假设在同一目录中),使用 PWD 命令:
pwd
使用 export 命令将脚本目录添加到 PATH 变量。
export PATH=$PATH:/home/louis/scripts
运行 hello.sh:
二、超详细shell脚本编程快速入门
1、shell变量
shell编程中,定义变量是直接定义的,没有明确的数据类型,shel允许用户建立变量存储数据,但是将认为赋给变量的值都解释为一串字符
shell中,英文符号"$"用于取变量值
注意点:shell编程的变量名的命名和其他语言一样,需要遵循一定的规则,规则如下
命名只能使用英文字母,数字和下划线,首个字符不能以数字开头
中间不能有空格,可以使用下划线(_)
不能使用标点符号
不能使用bash里的关键字(可用help命令查看保留关键字)
如下所示
有效的命令
NAME
LIBRARY_PATH
_var
var2
无效的命名
?var=123
user*name=ohuohuo
如果在变量中使用系统命令,需要加上 " `"符号(ESC键下方),如下所示
DATE1=`date`
DATE2=$(date)
两者功能相同
2、使用变量

3、变量操作
shell编程中也同样存在变量类型,在运行shell时会同时存在三种变量
局部变量:在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量
环境变量:所有的程序,包括shell启动的程序,都能访问环境变量,必要的时候shell脚本也可以定义环境变量
shell变量:由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,不同类型的变量保证了shell的正常运行
4、shell字符串
字符串类型

使用双引号的优势:
- 可以在双引号中使用变量
- 可以在双引号中使用转移字符
由此可见,双引号较单引号而言有更强大的优势
name="ohouhuoo"
str="please input your \"$name"\"
echo -e $str
echo -n 表示不换行输出
echo -e 将转义后的内容输出到屏幕上;

5、
-
获取字符串长度:在对变量进行取值时,使用" # "符号对字符串进行取值
-
string="abcd" echo ${#string} # 输出 4
-
提取子字符串:使用字符串的截取命令,用于提取部分字符串
-
string="this is a test" echo ${string:2:6} # 表示从第3个字符开始截取上式输出结果为
is is
查找字符串:用于查找字符的位置,输出结果为字符在字符串中所占的数据位置,如果查找多个字符,那哪个字母先出现就计算哪个,如下查找it中i和t两个字符,t先出现,输出为1
string="this is a test"
echo `expr index "$string" it` # 输出 1
6、shell数组
在bash下,仅仅支持一维数组,并且没有限定数组的大小,不支持多维数组。类似于 C 语言,数组元素的下标由 0 开始编号(上述字符串也是这样)。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于 0。
# 一般定义
array_name=(value1 value2 value3 value4)
# 多级定义
array_test=(
value1
value2
value3
value4
)
#
array_text[0]=value0
array_text[1]=value1
array_text[3]=value3
...
...
三种定义形式均可
数组操作
读取数组:和读取变量名相同,使用$符号,需要加上下标名
valuen=${array_name[n]}
echo ${array_name[@]} # 读取所有
获取数组长度:获取数组长度的方法与获取字符串长度的方法相同,如所示
# 取得数组元素的个数
length=${#array_name[@]} # 从头到尾取
# 或者
length=${#array_name[*]} # 取所有
# 取得数组单个元素的长度
lengthn=${#array_name[n]} # 取特定
shell传递参数
在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……,脚本编写如下,保存为test.sh
echo "传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
执行脚本如下
chmod +x test.sh
./test.sh 1 2 3
7、shell运算符
与其他编程语言相同的是,shell同样支持多种运算符:
算数运算符
关系运算符
布尔运算符
逻辑运算符
字符串运算符
文件测试运算符
shell想要使用这些运算符,需要结合其他命令和工具来使用(因为shell中不支持简单的数学运算),如使用算符运算符就需要搭配的常用的工具有两种
awk
expr(使用频繁)
运算规则注意点:
表达式和运算符之间必须要有空格,例如 3+2 是不对的,必须写成 3 + 2
完整的表达式要被 两个" ` "包含(在 Esc 键下边那个键)
如下实例
#!/bin/bash
val=`expr 3 + 2`
echo "两数之和为 : $val"
算数运算符

关系运算符

脚本编写如下
#!/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
需要注意的点:
- 运算符和数之间必须要用空格隔开
布尔运算符

逻辑运算符

需要注意的点:
- 这里使用两层的[ ]符号,将两次关系运算的结果保存在条件句中
字符串运算符
文件测试运算符
shell中的文件测试运算符用于检测在类unix系统中,文件的各种属性,如下表

#!/bin/bash
file="/var/www/test/test.sh"
if [ -r $file ]
then
echo "文件可读"
else
echo "文件不可读"
fi
8、shell编程中的命令
echo命令在shell中用于字符串的输出,调用的格式
shell中的printf命令如同C语言中一样,调用格式也大抵相同,只是有一点点不同。与echo命令打印字符串不同的是,printf不会自动调价换行符号,可以手动添加
$ echo "Hello, Shell" # 输入
Hello, Shell # 输出
$ printf "Hello, Shell\n" # 输入
Hello, Shell # 输出
shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试
#!/bin/bash
num1=100
num2=100
if test $[num1] -eq $[num2]
then
echo '两个数相等!'
else
echo '两个数不相等!'
fi
# !/bin/bas
num1="name"
num2="function"
if test $num1 = $num2
then
echo '两个字符串相等!'
else
echo '两个字符串不相等!'
fi
# !/bin/bash
if test -e ./bash
then
echo '文件已存在!'
else
echo '文件不存在!'
fi
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read num
case $num in
1) echo '你选择了 1'
;;
2) echo '你选择了 2'
;;
3) echo '你选择了 3'
;;
4) echo '你选择了 4'
;;
*) echo '你没有输入 1 到 4 之间的数字'
;;
esac
#!/bin/bash
while :
do
echo -n "输入 1 到 5 之间的数字:"
read num
case $num in
1|2|3|4|5) echo "你输入的数字为 $num!"
;;
*) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
break
;;
esac
done
for num in 1 2 3 4 5
do
echo "The value is: $num"
done
#!/bin/bash
num=1
while(( $num<=5 ))
do
echo $num
let "num++"
done
until 循环执行一系列命令直至条件为 true 时停止。until 循环与 while 循环在处理方式上刚好相反。一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。until循环调用格式:

9、shell函数
#!/bin/bash
FunReturn(){
echo "两个数字进行相加运算..."
echo "输入第一个数字: "
read num
echo "输入第二个数字: "
read anothernum
echo "两个数字分别为 $num 和 $anothernum !"
return $(($num+$anothernum)) # 分别返回数值
}
FunReturn # 调用函数
echo "输入的两个数字之和为 $? !" # 使用通配符获取上一条指令的返回值

10、 shell重定向
输入输出重定向
- 输入/输出重定向目的在于改变shell命令或者程序默认的标准输入/输出目标。重新定向到新的目标
- Linux中的默认的标注输入定义为从键盘输入,标准输出定义为从终端窗口输出
- 用于为当前操作改变输入或者输出,迫使某人特定命令的输入或者输出来源为外部文件

三、实战案例
#Shell常见的变量之二环境变量,主要是在程序运行时需要设置,环境变量详解如下:
PATH 命令所示路径,以冒号为分割;
HOME 打印用户家目录;
SHELL 显示当前Shell类型;
USER 打印当前用户名;
ID 打印当前用户id信息;
PWD 显示当前所在路径;
TERM 打印当前终端类型;
HOSTNAME 显示当前主机名;
PS1 定义主机命令提示符的;
HISTSIZE 历史命令大小,可通过 HISTTIMEFORMAT 变量设置命令执行时间;
RANDOM 随机生成一个 0 至 32767 的整数;
HOSTNAME 主机名
1.httpd安装函数
[root@web-server01~/script]# vim xx.sh
#!/bin/bash
#auto install apache
#By author rivers 2021-09-27
#Httpd define path variable
FILES=httpd-2.2.31.tar.bz2
LES_DIR=httpd-2.2.31
URL=http://mirrors.cnnic.cn/apache/httpd/
PREFIX=/usr/local/apache2/
function Apache_install ()
{
#Install httpd web server
if [[ "$1" -eq "1" ]];then
wget -c $URL/$FILES && tar -jxvf $FILES && cd $FILES_DIR &&./configure
if [ $? -eq 0 ];then
make && make install
echo -e "\n\033[32m--------------------------------------------
echo -e "\033[32mThe $FILES_DIR Server Install Success !\033[0m
else
echo -e "\033[32mThe $FILES_DIR Make or Make install ERROR,Plea
exit 0
fi
fi
}
Apache_install 1
# 调用函数,传参为1
2.遍历数组
#方法 1:
#!/bin/bash
IP=(10.0.0.1 10.0.0.2 10.0.0.3)
for ((i=0;i<${#IP[*]};i++)); do
echo ${IP[$i]}
done
# bash test.sh
10.0.0.1
10.0.0.2
10.0.0.3
#方法 2:
#!/bin/bash
IP=(10.0.0.1 10.0.0.2 10.0.0.3)
for IP in ${IP[*]}; do
echo $IP
done
3.自动打包备份
#!/bin/bash
#Auto Backup Linux System Files
#by author rivers on 2021-09-28
SOURCE_DIR=(
$*
)
TARGET_DIR=/data/backup/
YEAR=`date +%Y`
MONTH=`date +%m`
DAY=`date +%d`
WEEK=`date +%u`
A_NAME=`date +%H%M`
FILES=system_backup.tgz
CODE=$?
if
[ -z "$*" ];then
echo -e "\033[32mUsage:\nPlease Enter Your Backup Files or Directories\n--------------------------------------------\n\nUsage: { $0 /boot /etc}\033[0m"
exit
fi
#Determine Whether the Target Directory Exists
if
[ ! -d $TARGET_DIR/$YEAR/$MONTH/$DAY ];then
mkdir -p $TARGET_DIR/$YEAR/$MONTH/$DAY
echo -e "\033[32mThe $TARGET_DIR Created Successfully !\033[0m"
fi
#EXEC Full_Backup Function Command
Full_Backup()
{
if
[ "$WEEK" -eq "7" ];then
rm -rf $TARGET_DIR/snapshot
cd $TARGET_DIR/$YEAR/$MONTH/$DAY ;tar -g $TARGET_DIR/snapshot -czvf $FILES ${SOURCE_DIR[@]}
[ "$CODE" == "0" ]&&echo -e "--------------------------------------------\n\033[32mThese Full_Backup System Files Backup Successfully !\033[0m"
fi
}
#Perform incremental BACKUP Function Command
Add_Backup()
{
if
[ $WEEK -ne "7" ];then
cd $TARGET_DIR/$YEAR/$MONTH/$DAY ;tar -g $TARGET_DIR/snapshot -czvf $A_NAME$FILES ${SOURCE_DIR[@]}
[ "$CODE" == "0" ]&&echo -e "-----------------------------------------\n\033[32mThese Add_Backup System Files $TARGET_DIR/$YEAR/$MONTH/$DAY/${YEAR}_$A_NAME$FILES Backup Successfully !\033[0m"
fi
}
sleep 3
Full_Backup;Add_Backup
4.服务器系统信息自动收集
cat <<EOF
++++++++++++++++++++++++++++++++++++++++++++++
++++++++Welcome to use system Collect+++++++++
++++++++++++++++++++++++++++++++++++++++++++++
EOF
ip_info=`ifconfig |grep "Bcast"|tail -1 |awk '{print $2}'|cut -d: -f 2`
cpu_info1=`cat /proc/cpuinfo |grep 'model name'|tail -1 |awk -F: '{print $2}'|sed 's/^ //g'|awk '{print $1,$3,$4,$NF}'`
cpu_info2=`cat /proc/cpuinfo |grep "physical id"|sort |uniq -c|wc -l`
serv_info=`hostname |tail -1`
disk_info=`fdisk -l|grep "Disk"|grep -v "identifier"|awk '{print $2,$3,$4}'|sed 's/,//g'`
mem_info=`free -m |grep "Mem"|awk '{print "Total",$1,$2"M"}'`
load_info=`uptime |awk '{print "Current Load: "$(NF-2)}'|sed 's/\,//g'`
mark_info='BeiJing_IDC'
echo -e "\033[32m-------------------------------------------\033[1m"
echo IPADDR:${ip_info}
echo HOSTNAME:$serv_info
echo CPU_INFO:${cpu_info1} X${cpu_info2}
echo DISK_INFO:$disk_info
echo MEM_INFO:$mem_info
echo LOAD_INFO:$load_info
echo -e "\033[32m-------------------------------------------\033[0m"
echo -e -n "\033[36mYou want to write the data to the databases? \033[1m" ;read ensure
if [ "$ensure" == "yes" -o "$ensure" == "y" -o "$ensure" == "Y" ];then
echo "--------------------------------------------"
echo -e '\033[31mmysql -uaudit -p123456 -D audit -e ''' "insert into audit_system values('','${ip_info}','$serv_info','${
cpu_info1} X${cpu_info2}','$disk_info','$mem_info','$load_info','$mark_info')" ''' \033[0m '
mysql -uroot -p123456 -D test -e "insert into audit_system values('','${ip_info}','$serv_info','${cpu_info1} X${cpu_info2}
','$disk_info','$mem_info','$load_info','$mark_info')"
else
echo "Please wait,exit......"
exit
fi
5.批量部署lnmp
[root@web-server01~/script]# vim lnmp.sh
#!/bin/bash
#install lnmp
#by author rivers on 2021-9-28
# nginx 环境准备
Nginx_url=https://nginx.org/download/nginx-1.20.1.tar.gz
Nginx_prefix=/usr/local/nginx
# mysql 环境准备
Mysql_version=mysql-5.5.20.tar.gz
Mysql_dir=mysql-5.5.20
Mysql_url=https://downloads.mysql.com/archives/get/p/23/file/mysql-5.5.20.tar.gz
Mysql_prefix=/usr/local/mysql/
# php 环境准备
Php_version=php-7.2.10.tar.gz
Php_prefix=/usr/local/php-7.2.10/
function nginx_install(){
if [[ "$1" -eq "1" ]];then
if [ $? -eq 0 ];then
make && make install
fi
fi
}
function mysql_install(){
if [[ "$1" -eq "2" ]];then
-DMYSQL_UNIX_ADDR=/tmp/mysql.sock \
-DMYSQL_DATADIR=/data/mysql \
-DSYSCONFDIR=/etc \
-DMYSQL_USER=mysql \
-DMYSQL_TCP_PORT=3306 \
-DWITH_XTRADB_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_READLINE=1 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_EXTRA_CHARSETS=1 \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DEXTRA_CHARSETS=all \
echo -e "\033[32mThe $Mysql_dir Server Install Success !\033[0m"
else
echo -e "\033[32mThe $Mysql_dir Make or Make install ERROR,Please Check......"
exit 0
fi
/bin/cp support-files/my-small.cnf /etc/my.cnf
/bin/cp support-files/mysql.server /etc/init.d/mysqld
chmod +x /etc/init.d/mysqld
chkconfig --add mysqld
chkconfig mysqld on
fi
}
function php_install(){
if [[ "$1" -eq "3" ]];then
if [ $? -eq 0 ];then
make ZEND_EXTRA_LIBS='-liconv' && make install
if [[ "$1" -eq "3" ]];then
wget $Php_url && tar xf $Php_version && cd $Php_dir && yum install bxml2* bzip2* libcurl* libjpeg* libpng* freetype* gmp* libm
crypt* readline* libxslt* -y && ./configure --prefix=$Php_prefix --disable-fileinfo --enable-fpm --with-config-file-path=/etc --wi
-config-file-scan-dir=/etc/php.d --with-openssl --with-zlib --with-curl --enable-ftp --with-gd --with-xmlrpc --with-jpeg-dir --w
ith-png-dir --with-freetype-dir --enable-gd-native-ttf --enable-mbstring --with-mcrypt=/usr/local/libmcrypt --enable-zip --enable-
mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --with-mysql-sock=/var/lib/mysql/mysql.sock --without-pear --enable-bcmath
if [ $? -eq 0 ];then
make ZEND_EXTRA_LIBS='-liconv' && make install
echo -e "\n\033[32m-----------------------------------------------\033[0m"
echo -e "\033[32mThe $Php_version Server Install Success !\033[0m"
else
echo -e "\033[32mThe $Php_version Make or Make install ERROR,Please Check......"
exit 0
fi
fi
}
PS3="Please enter you select install menu:"
select i in nginx mysql php quit
do
"lnmp.sh" 113L, 3516C written
[root@web-server01~/script]# vim lnmp.sh
chkconfig --add mysqld
chkconfig mysqld on
fi
}
function php_install(){
if [[ "$1" -eq "3" ]];then
if [ $? -eq 0 ];then
make ZEND_EXTRA_LIBS='-liconv' && make install
echo -e "\n\033[32m-----------------------------------------------\033[0m"
echo -e "\033[32mThe $Php_version Server Install Success !\033[0m"
else
echo -e "\033[32mThe $Php_version Make or Make install ERROR,Please Check......"
exit 0
fi
fi
}
PS3="Please enter you select install menu:"
select i in nginx mysql php quit
do
case $i in
nginx)
nginx_install 1
;;
mysql)
mysql_install 2
;;
php)
php_install 3
;;
quit)
exit
esac
done

2404

被折叠的 条评论
为什么被折叠?



