目录
什么是shell,他是一个命令解释器,介于linux系统和用户之间的绝缘层。它的作用就是把你需要执行的各种命令放在一个.sh文件中,然后一次性执行的一个程序文件。
一、开头
创建一个.sh文件就可以编写shell脚本了,但是文件的第一行必须是以下命令
#!/bin/bash
(这个bash是终端的版本,本案例使用bash版本)
文件编辑完成后并不能运行,因为没有运行权限,因此要给他加上可执行权限
chomd +x 文件名.sh
然后./文件名.sh就能运行了
二、注释
shell中注释与c有所不同,他只有一种注释,即以#开头便是注释,到这一行结束。
三、变量
shell所有的变量都有字符串组成,并且不需要提前声明。一共有四种变量分别是用户自定义变量,位置参数即命令行参数,预定义变量,环境变量。
1>用户自定义变量
shell中可以自定义变量,但是它没有数据类型,任何赋予自定义变量的值都会被shell解释为一串字符串。它的命名规则与c相同
~ 由字母、数字以及下划线(_)组成,首字母不能为数字
~ 不能为关键字和保留字
~ 尽量见名知意
给变量赋值
变量名=值
这里等号两边不能有空格,而且shell中通常使用全大写来写变量;
若要取变量的值可以用$符号,例如我定义一个变量COUNT
COUNT=2
echo "this is the $COUNTnd"
是不是以为他会打印this is the 2nd
shell并不知道COUNDnd的值,因此需要给他加上{},即
COUNT=2
echo "this is the {$COUN}nd"
使用unset命令可删除变量的赋值
upset COUNT
他的值就会被撤销
2>预定义变量
当执行一个 Shell 脚本时,如果希望获取到命令行的参数信息,就需要使用到位置参数变量。基本语法有:
$# :代表命令行中所有参数的个数(命令不记在参数内)
$n :n 为数字,$0 代表命令本身,$1-9 代表第 1 到第 9 个参数,10 以上的参数需要用大括号包含如 ${10}
$*:代表命令行中的所有参数,$* 将所有参数看成一个整体
$@ :这个变量也可以代表命令行中的所有参数,不过 $@ 把每个参数区分对待$?:包含前一个命令的退出状态,正常退出返回0,反之则为非0值
$$:包含正在执行进程的id号
#!/bin/bash
# 获取命令行参数的个数
echo "Number of arguments: $#"
# 输出命令本身
echo "Script name: $0"
# 输出前3个命令行参数
echo "First argument: $1"
echo "Second argument: $2"
echo "Third argument: $3"
# 输出所有命令行参数作为一个整体
echo "All arguments as a whole: $*"
# 使用$@遍历并输出每个命令行参数
echo "Iterating through arguments using \$@:"
for arg in "$@"; do
echo "$arg"
done
# 执行一个命令并检查退出状态
ls /some/nonexistent/directory
exit_status=$?
if [ $exit_status -eq 0 ]; then
echo "Command succeeded"
else
echo "Command failed with exit status: $exit_status"
fi
# 输出前一个命令的退出状态
echo "Exit status of previous command: $?"
# 输出当前执行进程的进程ID
echo "Current process ID: $$"
$ bash script.sh arg1 arg2 arg3
Number of arguments: 3
Script name: script.sh
First argument: arg1
Second argument: arg2
Third argument: arg3
All arguments as a whole: arg1 arg2 arg3
Iterating through arguments using $@:
arg1
arg2
arg3
ls: cannot access '/some/nonexistent/directory': No such file or directory
Command failed with exit status: 2
Exit status of previous command: 2
Current process ID: <当前进程ID>
请注意,<当前进程ID>
是一个占位符,实际运行时将显示当前执行进程的进程ID。
3>位置参数
位置参数是指在Shell脚本中传递给脚本的命令行参数的值,它们按照其出现的顺序进行编号。在Shell脚本中,可以使用特殊变量 $1
、$2
、$3
等来引用这些位置参数。
假设我们有一个名为 script.sh
的Shell脚本,我们可以在命令行中传递参数给它:
$ bash script.sh arg1 arg2 arg3
在脚本中,可以通过 $1
、$2
、$3
来访问这些位置参数的值。
#!/bin/bash
echo "First argument: $1"
echo "Second argument: $2"
echo "Third argument: $3"
输出:
First argument: arg1
Second argument: arg2
Third argument: arg3
4>环境变量
环境变量是在操作系统环境中定义的一些全局变量,可以影响程序的行为和系统的操作。在Shell脚本中,可以使用这些环境变量来获取系统的信息、配置程序的行为和传递数据。
以下是一些常见的环境变量及其作用:
PATH
:用于指定可执行程序的搜索路径。当你在命令行中输入一个命令时,操作系统会在PATH
指定的路径下查找可执行文件。
HOME
:表示当前用户的主目录路径。通常用于存储用户的个人文件和配置。
USER
和USERNAME
:表示当前登录用户的用户名。
SHELL
:表示当前用户所使用的Shell程序的路径。
PWD
:表示当前工作目录的路径。
LANG
和LC_*
:用于设置区域设置(Locale)和语言环境。
TMP
和TEMP
:表示临时文件所存放的路径。
PS1
:用于定义命令提示符的格式。
我们可以通过$变量名
的方式来引用环境变量的值。例如,$PATH
引用了PATH
环境变量的值。
同时,也可以在脚本中使用export
命令来定义和设置自己的环境变量。例如,export MY_VAR="Hello"
将定义一个名为MY_VAR
的环境变量,其值为Hello
。
四、shell程序和语句
一个shell语句由多条shell语句构成,shell语句包括三个类型:说明语句、功能性语句、和结构性语句。
1>说明性语句
即注释行,他可以在任何位置,可单独一行,也可在语句末尾行。以#号开头,到所在行的末尾结束,就是这句话不被执行。
2>功能性语句
shell中变量赋值具有一定的局限性,我们经常需要从外部获取变量的值,可采取键盘输入变量值。
(1)键盘读入变量值
read [-options] [variable...]
-options
是可选的参数,用于指定read
命令的行为。常用的选项包括:
-p prompt
:用于指定一个提示符,显示给用户,等待用户输入。-s
:使输入的内容在终端上不可见(用于输入密码等敏感信息)。-r
:将用户输入的内容原样存储,不进行转义。-a array
:将连续的多个输入赋值给一个数组变量。variable
是要接收用户输入值的变量名称。用户的输入将赋值给相应的变量。
例如
#!/bin/bash
read -p "Please enter your name: " name
echo "Hello, $name!"
也可以输入多个变量
#!/bin/bash
read -p "Please enter your first name and last name: " first last
echo "Hello, $first $last!"
(2)算术运算命令
它和C语言有所不同,他不能直接使用+-*/
他需要在命令前加expr命令,再使用加(+)减(-)乘(\*)整除(/)求模(%)
例如
result=`expr 10 + 5` # 加法
result=`expr 10 - 5` # 减法
result=`expr 10 \* 5` # 乘法,需要使用反斜杠转义*
result=`expr 10 / 5` # 除法
result=`expr 10 % 5` # 取模
实例中 ` 为键盘左上角的反引号 【`】键
(3)test命令
test语句可测试三种对象:字符、整数、文件属性
test
命令可以以多种不同的方式使用,常见的用法是通过中括号 [ ]
或双括号 [[ ]]
进行条件判断。(注意:“ [ ”左边以及“ ] ”右边都需要加一个空格)
if [ condition ]; then
# 条件满足时执行的代码块
fi
&字符串测试
s1 = s2 判断两个字符串的内容是否相同
s1! = s2 判断两个字符串的内容是否不相同
-z s 判断字符串s的长度是否为零
-n s 判断字符串s的长度是否不为零
注意:=和!= 两边有留有至少一个空格 否则就是赋值语句,永远为真。
&整数测试
a -eq b 判断两个数字是否相同
a -ne b 判断两个数字是否不相同
a -gt b 判断a是否大于b
a -ge b 判断a是否大于等于b
a -lt b 判断a是否小于b
a -le b 判断a是否小于等于b
&文件测试
-e file
:判断文件是否存在。-f file
:判断文件是否为普通文件。-L file
:判断文件是否是软链接文件的操作符-d file
:判断文件是否为目录。-r file
:判断文件是否存在且可读。-w file
:判断文件是否存在且可写。-x file
:判断文件是否存在且可执行。-s file
:判断文件是否非空。
判断文件是否为空示例
ls file
exit_status=$?
if [ $exit_status -eq 0 ]; then
echo "命令执行成功"
else
echo "命令执行失败"
fi
3>结构性语句
结构性语句是指用于控制程序流程的语句,常见的结构性语句包括条件语句(if语句)、循环语句(for循环、while循环)和函数等
&条件测试语句
if [ condition ]
then
# 执行条件满足时的代码块
else
# 执行条件不满足时的代码块
fi
if [ $num -gt 10 ]; then
echo "数字大于10"
else
echo "数字不大于10"
fi
case expression in
pattern1)
# 匹配 pattern1 时执行的代码块
;;
pattern2)
# 匹配 pattern2 时执行的代码块
;;
pattern3)
# 匹配 pattern3 时执行的代码块
;;
*)
# 默认情况下执行的代码块
;;
esac
read -p "请输入一个数字:" num
case $num in
1)
echo "输入的是数字1"
;;
2)
echo "输入的是数字2"
;;
3|4|5)
echo "输入的是3、4或5"
;;
*)
echo "输入的是其他数字"
;;
esac
&循环语句
for 变量名 in 单词表
do
# 执行循环体内的代码块
done
for i in 1 2 3 4 5; do
echo "循环次数: $i"
done
while 命令或表达式
do
# 执行循环体内的代码块
done
count=0
while [ $count -lt 5 ]; do
echo "循环次数: $count"
count=`expr $count + 1`
done
4>break与continue
break
使用 while、until、for 循环时,如果想提前结束循环(在不满足结束条件的情况下结束循环),可以使用 break 或者 continue 关键字。
break n
n 表示跳出循环的层数,如果省略 n,则表示跳出当前的整个循环。
#!/bin/bash
declare -i sum
for ((i=1; i<=100; i++))
do
sum+=i
if [ $i -eq 10 ];then
break;
fi
done
echo "The sum is: $sum"
continue
continue n
n 表示循环的层数:
如果省略 n,则表示 continue 只对当前层次的循环语句有效,遇到 continue 会跳过本次循环,忽略本次循环的剩余代码,直接进入下一次循环。
如果带上 n,比如 n 的值为 2,那么 continue 对内层和外层循环语句都有效,不但内层会跳过本次循环,外层也会跳过本次循环,其效果相当于内层循环和外层循环同时执行了不带 n 的 continue。
#!/bin/bash
declare -i sum
for ((i=1; i<=100; i++))
do
if [ $i -eq 10 ];then
continue;
fi
sum+=i
done
echo "The sum is: $sum"
五、shell函数
1>函数的定义格式
方式一
函数名()
{
函数体
}
方式二
function 函数名()
{
函数体
}
2>函数调用格式
方式一
value_name=`function_name arg1 arg2`
变量名=`函数名 参数1 参数2`
函数的所有标准输出都传递给了主程序的
方式二
function_name arg1 arg2
函数名 参数1 参数2
echo $? # $?上一个命令退出的状态
六、案例
一、案例一
#!/bin/bash
#若命令下无参数,将该目录下的文件复制到backup中去
#若命令下有一个参数,查找该文件是否在该文件夹中
if [ ! -d $HOME/backup ] #判断$HOME/backup 创建thenmkdir
$HOME/backup
fi
flist=`ls` #将ls的运行结果赋值给flist
for file in $flist #遍历ls的结果
do
if [ $# = 1 ] #若命令行下有1个参数
then
if [ $1 = $file ] #判断你传入的参数在该路径下若存在
then
echo "$file found";exit
fi
else #若命令下无参数
cp $file $HOME/backup
echo "$file copied"
fi
done
#若命令下无参数,将该目录下的文件复制到backup中去
#若命令下有一个参数,查找该文件是否在该文件
二、案例二
#!/bin/bash
#判断用户主目录下是否有file_dir dir_dir两个目录
#如果这两个目录存在询问是否删除这两个目录
#若用户输入Y删除目录创建新的file_dir和dir_dir目录
#如果输入的为N退出程序
#请用户输入一个路径,将这个路径下的文件拷贝到file_dir,目录拷贝到dir_dir
#统计拷贝文件以及目录的个数
for dir in $HOME/file_dir $HOME/dir_dir
do
if [ -d $dir ]
then
read -p "是否删除目录$dir
" OP
case $OP in
Y|y)
rm -rf $dir
mkdir $dir
echo "创建$dir成功"
;;
N|n)
exit
;;
esac
else #文件不存在
make $dir
echo "创建$dir成功"
fi
done
read -p "请输入一个绝对路径
" path
NUM1=0
NUM2=0
Flist=`ls $path` #显示文件夹中的文件和目录
for file in $Flist
do
if [ -f $path/$file ]
then
cp $path/$file $HOME/file_dir
NUM1=`expr $NUM1 + 1`
echo "$file copied"
elif [ -d $path/$file ]
then
cp -r $path/$file $HOME/dir_dir
NUM2=`expr $NUM2 + 1`
echo "$file copied"
fi
done
echo "文件有$NUM1个,目录有$NUM2个"