如何执行脚本
在脚本中指定解释器
可以在文件第一行 ,之前不能有回车
#! 解释器路径
例子
vi shell_1
#! /usr/local/miniconda3/bin/python3.7 print("这是在文件开始指定了python3解释器的文件")
执行这个脚本文件
./shell_1 sh: ./shell_1: Permission denied 说明权限不够 分配给他权限 chmod +x ./shell_1 或者直接 chmod 777 shell_1 再次执行 ./shell_1 这是在文件开始指定了python3解释器的文件 绝对路径执行 /home/shellStudy/shell_1 这是在文件开始指定了python3解释器的文件
直接在执行时指定解释器
这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。
python3 shell_1 这是在文件开始指定了python3解释器的文件
linux 自带的解释器 /bin/bash
sh-4.2# /bin/bash
(base) [root@20351ba90c2a shellStudy]#
接下来,来学习/bin/bash 的 shell 语法
为什么执行要写作 ./ file
注意,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,
直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,
要用 ./test.sh 告诉系统说,就在当前目录找。
Bourne Again Shell(/bin/bash) 的语法
变量
定义变量
注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:
命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
中间不能有空格,可以使用下划线(_)。
不能使用标点符号。
不能使用bash里的关键字(可用help命令查看保留关键字)。
sh-4.2# var1="what are you doing now?" sh-4.2# 没有报错说明定义成功
变量可以被重复定义
使用定义过的变量
使用变量前需要在变量之前加上${ var }
外边的 大括号 最好都加上。这样可以防止一些特殊情况的出现
当然了 $var 后边加空格分开变量,也是可以的
sh-4.2# echo $var1 what are you doing now?
简单循环中的变量
for skill in pyhton C C++ Java; do echo "I am good at $skill language" done I am good at pyhton language I am good at C language I am good at C++ language I am good at Java language
只读变量
当定义了一个变量以后,可以使用readonly var 来将变量变成只读变量
readonly var
删除变量
unset var
变量类型
运行shell时,会同时存在三种变量:
- 局部变量 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
var1="this is 局部变量"
- 环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
java 输出 用法:java [options] <主类> [args...]
- shell变量 shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
字符串变量
单引号字符串
str=‘this is a string’
单引号字符串的限制:
单引号里的任何字符都会原样输出,
单引号字符串中的变量是无效的;
单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
双引号字符串:
双引号里可以有变量
双引号里可以出现转义字符
当字符串中 嵌入 变量时,单双引号的差别
sh-4.2# var1="早上" sh-4.2# var10="$var1 吃饼" sh-4.2# var11='$var1 喝茶' sh-4.2# echo $var10 $var11 早上 吃饼 $var1 喝茶
获取字符长度
${#varname}
sh-4.2# echo ${#var1} 2
for tempvar in asasas asasasasas qwqwqw ;do echo ${#tempvar}; done; 6 10 6
提取字符串子串
${var: 起始位置 : 截取多少个字符 }
var1="今天早上出去吃了豆浆油条" sh-4.2# varson=${var1:0:3} sh-4.2# echo $varson 今天早
从0开始截取4个字符
sh-4.2# varson=${var1:0:4} sh-4.2# echo $varson 今天早上
从1开始截取4个字符
sh-4.2# varson=${var1:1:4} sh-4.2# echo $varson 天早上出
参数传递
单个获取参数
在执行脚本的时候我们通常会向脚本内部传入变量
传入后,可以在脚本内部使用 $n 来得到传入参数 n
$0代表当前执行的文件名称
参数方法
$# 传递到脚本的参数个数 $@ 以"$1" "$2" … "$n" 的形式输出所有参数。 $* 以一个单字符串显示所有向脚本传递的参数。 $$ 代表当前进程的pid $! 最近一个后台进程的pid
$* 与 $@ 区别:
相同点:都是引用所有参数。
不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,
则 " * " 等价于 “1 2 3”(传递了一个参数)
,而 “@” 等价于 “1” “2” “3”(传递了三个参数)。
循环遍历输出参数
vi shell_get_para…sh
for var1 in $@ ; do echo $var1 ; done ;
运行输出
./shell_get_para.sh 参数1 参数2 参数1 参数2
数组
创建数组与访问数组
shell 只支持1维数组
创建方法1 listname=(var1 var2 … var3) 变量之间使用空格间隔
list1=( 1 'a' 'b' 'good' )
根据下表创建数组,下标可以不是连续的,shell中的数组不会进行边界检查,当下标不存在变量的时候,会直接返回空
my_array[0]="a0" my_array[3]="a3" 输出数组长度 echo ${#my_array} 输出数组变量内容 echo ${my_array[@]} a0 a3 注意直接访问数组,只会返回数组的第一个元素 echo ${my_array} a0 遍历数组中的变量 for onevar in ${list1[*]} ;do echo $onevar ; done;
运算符
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,
例如 awk 和 expr,expr 最常用。
val=`expr 2 + 2` echo $val 4
表达式和运算符之间要有空格,
例如 2+2 是不对的,必须写成 2 + 2,
这与我们熟悉的大多数编程语言不一样。
完整的表达式要被 ` 包含,注意这个字符不是常用的单引号,在 Esc 键下边。
a0=10 ; b0=20; 加减 echo `expr $a0 + $b0` 30 乘法 乘法运算符是 \* 运算符两侧的操作数必须要有,k'm echo `expr $a0 \* $b0` 200 除法操作 echo `expr $a0 / $b0` 0 取余操作 echo `expr $a0 % $b0` 0 a0=$b0 echo $a0 20
比较符号以及逻辑符号
-eq 相等 -ne 不相等 -gt > 于号 -gt是大于 -lt是小于 -eq是等于 -ne是不等于 -ge是大于等于 -le是小于等于 !非 -o 或 -a 与 && 与 || 或
检测文件
-r file 检测文件是否可读,如果是,则返回 true。 -w file 检测文件是否可写,如果是,则返回 true。 -x file 检测文件是否可执行,如果是,则返回 true。 -s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 -e file 检测文件(包括目录)是否存在,如果是,则返回 true。
特殊命令
echo 命令
echo "\"It is a test\""
echo 重定向到 环境变量 配置文件 /etc/profile
//将某个目录添加到 环境变量 里来 echo " export PATH=$PATH:/usr/local/miniconda3/bin " >> /etc/profile
read 命令
read name1 asd echo $name1 asd
printf 命令
./shell_printf.sh 文件内容如下 printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234 printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543 printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876 ./shell_printf.sh 姓名 性别 体重kg 郭靖 男 66.12 杨过 男 48.65 郭芙 女 47.99
test命令
用来检测命令
if test -e ./bash
-e 文件名 如果文件存在则为真
控制结构
if then ... elif ... else ..... fi
写做一行
if [ 20 -eq 20 ] ;then echo "yes" ;fi yes
假设目录下存在 shell_1 ,不存在 shell_2
if test -e shell_1 ;then echo "yes"; else echo "no this file " ;fi yes if test -e shell_2 ; then echo "yes" ; else echo "no this file " ;fi no this file
if 后边的条件如果不使用test命令,必须要 if 空格 [space 条件 space];then
fi
if [ $i<10 ]
循环结构
for var in item1 item2 ... itemN do command1 command2 ... commandN done
输出当前目录下的文件的目录
for var in `cd .. && ls `; do echo $var; done; c
while 循环 (( condition )) 必须是双括号
循环输出 i = 1,2,3,4,5 方法一 i=1; while(( $i<=5 )); do echo "$i"; i=` expr $i + 1 `; done 方法而 i=1;while(($i<=5));do echo $i ; let i=i+1 ;done
死循环
i=0
while :
do
echo $i
let i=i+1
if [ $i>3 ]
then
break
fi
done
使用if 跳出while循环
i=0; while true; do let i=i+1 ; echo $i ; if [ $i -eq 3 ]; then break; fi; done