目录
参考菜鸟教程,把shell编程总结下。
编辑和运行shell脚本
编辑
编辑器:vim pycharm vscode等等能够编写代码的文本编辑器
运行
解释器:Linux 的 Shell 种类众多,常见的有:
- Bourne Shell(/usr/bin/sh或/bin/sh)
- Bourne Again Shell(/bin/bash)
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
- Shell for Root(/sbin/sh)
运行方式一般有两种:
- 在代码开头加上默认的解释器,如
#!/usr/bin/env bash
然后将shell脚本文件改为可执行文件
chmod +x xx.sh
就可以直接用
./xx.sh #当前路径是必须写出来的,因为$PATH中并没有当前路径,shell找不到
运行了。
shell变量
命名规则
- 只由(大写、小写)英文字母,数字,下划线组成
- 不能用数字开头
- 不能使用bash保留的关键字,可使用
bash -c help
查看所有关键字。
建改删用
- 创建一个没有的shell变量
my_var="good" #不要在等式两边留有任何空格
- 改变一个已有的shell变量
(1)改变量的值
my_var="good"
my_var="bad" #改为“bad”了
(2)改权限
my_var="good"
readonly my_var #改为只读,这样就不能被修改,也不能被删除
- 删除一个已有的变量
my_var="good"
unset my_var
- 使用变量的值
my_var="good"
echo this is a ${my_var} day. #加上花括号,限定变量名的界限,以免引起混乱
shell字符串
- 单引号中的所有字符都保持原样,不涉及转义或取变量的值
- 双引号中涉及转义和取变量的值
- 也可以不用引号
- 拼接字符串:
your_name="runoob"
# 使用双引号拼接
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting $greeting_1
# 使用单引号拼接
greeting_2='hello, '$your_name' !'
greeting_3='hello, ${your_name} !'
echo $greeting_2 $greeting_3
输出为:
hello, runoob ! hello, runoob !
hello, runoob ! hello, ${your_name} !
注意第三个使用单引号的拼接方式
- 获取字符串长度
your_name="runoob"
echo ${#your_name} # 6
- 字符串切片
string="runoob is a great site"
echo ${string:1:4} # 输出unoo,即从编号1开始的4个字符,注意shell的字符串从0开始编号,这一点和python一致
echo ${string:2} # 输出noob is a great site,即从编号2开始的所有字符
- 字符串查找
string="runoob is a great site"
echo `expr index "${string}" io` # 输出4,即i或者o最开始出现的地方,注意这时候index从1开始计算,而不是0
shell数组
- 定义方法
(1) 使用空格作为分隔符
array_name=(value0 value1 value2 value3)
echo ${array_name[0]} # 输出value0
(2)使用换行作为分隔符
array_name=(
value0
value1
value2
value3
)
(3) 直接对下标进行赋值,注意shell数组的编号可以不连续,有什么就用什么,没有的下标也可以取值,但是是空的
array_name[0]=value0
array_name[1]=value1
array_name[5]=value5
echo ${array_name[@]}
echo try 2
echo ${array_name[2]}
echo try 5
echo ${array_name[5]}
输出为:
value0 value1 value5
try 2
try 5
value5
- 长度
array_name[0]=value0
array_name[1]=value1
array_name[5]=value5
# 取得数组元素的个数
length=${#array_name[@]}
echo first length: ${length}
# 或者
length=${#array_name[*]}
echo second length: ${length}
# 取得数组单个元素的长度
length5=${#array_name[5]}
echo one string length: ${length5}
输出为:
first length: 3
second length: 3
one string length: 6
shell注释
- 单行注释,使用#开头
- 多行注释
:<<EOF # 使用EOF
echo here is a comment
EOF
echo it is not a comment
:<<! # 使用!
# 或者
length=${#array_name[*]}
echo second length: ${length}
# 取得数组单个元素的长度
length5=${#array_name[5]}
echo one string length: ${length5}
!
传递参数
- $0表示文件名,$1表示第一个命令行参数,$2表示第二个命令行参数。。。
- $#表示传到脚本的命令行参数个数
- "$*"以一个单字符串显示所有向脚本传递的参数
- "$@"以字符串数组显示所有向脚本传递的参数
运算
算术运算
注意: 算术运算可以如下写
#!/bin/bash
a=5
b=6
result=$[a+b] # 注意等号两边不能有空格
echo "result 为: $result" # 11
关系运算
布尔运算和逻辑运算
字符串运算
注意:>、<、==、!= 也可以进行字符串比较,只不过这个时候需要使用[[ ]]来进行条件判断,而且里面的逻辑运算要用&&和||,另外逻辑非!此时也可用
#!/bin/bash
a="heri"
b="here"
if [[ $a < $b ]]
then
echo 'a<b'
else
echo 'a>=b'
fi
if [[ $a == $b ]]
then
echo 'a=b'
else
echo 'a!=b'
fi
文件测试运算符
# 如果没有目录"TCGA/breast",就创建它
if [ ! -d "TCGA/breast" ]
then
mkdir "TCGA/breast"
fi
打印命令
echo命令
输出字符串,自动添加换行符
- 单引号不转义
echo 'ok, this is \"cp\".\n'
echo 'yes.'
#result:
#ok, this is \"cp\".\n
#yes.
- 双引号转义",但是不转义\n
echo "ok, this is \"cp\".\n"
echo "yes."
#ok, this is "cp".\n
#yes.
- -e 强制转义
echo -e "ok, this is \"cp\".\n"
echo "yes."
#ok, this is "cp".
#
#yes.
printf命令
输出字符串,不自动添加换行,但是格式化能力强
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com
# format-string为双引号
printf "%d %s\n" 1 "abc"
# 单引号与双引号效果一样
printf '%d %s\n' 1 "abc"
# 没有引号也可以输出
printf %s abcdef
# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用
printf %s abc def
printf "%s\n" abc def
printf "%s %s %s\n" a b c d e f g h i j
# 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替
printf "%s and %d \n"
#result:
#1 abc
#1 abc
#abcdefabcdefabc
#def
#a b c
#d e f
#g h i
#j
# and 0
shell函数
函数定义
#1:
demoFun(){
echo "这是我的第一个 shell 函数!"
}
#2:
funWithReturn(){
echo "这个函数会对输入的两个数字进行相加运算..."
echo "输入第一个数字: "
read aNum
echo "输入第二个数字: "
read anotherNum
echo "两个数字分别为 $aNum 和 $anotherNum !"
return $(($aNum+$anotherNum)) # 带return
}
参数和返回值
- 函数返回值在调用该函数后通过 ? 来 获 得 , 需 要 立 即 保 存 , 否 则 就 不 能 再 看 到 了 。 当 有 r e t u r n 时 , r e t u r n 的 必 须 是 0 − 255 的 整 数 , ? 来获得,需要立即保存,否则就不能再看到了。当有return时,return的必须是0-255的整数, ?来获得,需要立即保存,否则就不能再看到了。当有return时,return的必须是0−255的整数,?获得return的整数;当没有return时,$?获得函数最后一条命令运行成功与否的值,成功为0,不成功为1.
#!/bin/bash
function demoFun1(){
echo "这是我的第一个 shell 函数!"
return `expr 1 + 1`
}
demoFun1
echo $?
function demoFun2(){
echo "这是我的第二个 shell 函数!"
expr 1 + 1
}
demoFun2
echo $?
demoFun1
echo 在这里插入命令!
echo $?
# 结果:
# 这是我的第一个 shell 函数!
# 2
# 这是我的第二个 shell 函数!
# 2
# 0
# 这是我的第一个 shell 函数!
# 在这里插入命令!
# 0
- 函数参数用${n}获取
- 函数参数数目用$#获取
test命令
检查条件是否满足
- 数值
num1=100
num2=100
if test $[num1] -eq $[num2]
then
echo '两个数相等!'
else
echo '两个数不相等!'
fi
- 字符串
num1="ru1noob"
num2="runoob"
if test $num1 = $num2
then
echo '两个字符串相等!'
else
echo '两个字符串不相等!'
fi
- 文件
cd /bin
if test -e ./bash
then
echo '文件已存在!'
else
echo '文件不存在!'
fi
- 多重条件
Shell还提供了与( -a )、或( -o )、非( ! )三个逻辑操作符用于将测试条件连接起来,其优先级为:"!“最高,”-a"次之,"-o"最低。
cd /bin
if test -e ./notFile -o -e ./bash
then
echo '至少有一个文件存在!'
else
echo '两个文件都不存在'
fi
输入输出重定向
标准输入(stdin)的文件描述符为0,标准输出(stdout)的文件描述符为1,标准错误(stderr)的文件描述符为2。通过重定向,可以从文件读数据,并且输出到文件。
重定向标准输入,标准输出
- 改写方式
wl -l < file > file2 # 从file中读取数据,返回行数, 如56 输出到文件file2,文件file2原来的内容会被覆盖
- 追加方式
wl -l < file >> file2 # 从file中读取数据,返回行数, 如56 输出追加到文件file2末尾
重定向标准输出和标准错误到一个位置
wl -l < file > file2 2>&1 # 从file中读取数据,返回行数, 如56 输出到文件file2,如果命令出错,把出错信息返回到file2
交互式(多行)输入
$ wc -l << EOF # 在shell中交互输入
欢迎来到
菜鸟教程
www.runoob.com
EOF
3 # 返回命令结果
或者
#!/bin/bash
wc -l << EOF
欢迎来到
菜鸟教程
www.runoob.com
EOF
不要显示输出
当不想要显示输出时,重定向到/dev/null
wl -l < file > /dev/null 2>&1
导入其他文件
封装公用部分为file,在其他文件中使用时,只需要导入这个shell文件就行了。有两种写法
. file
#或者
source file
第一个shell文件为
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com
url="http://www.runoob.com"
第二个shell文件为
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com
#使用 . 号来引用test1.sh 文件
. ./test1.sh
# 或者使用以下包含文件代码
# source ./test1.sh
echo "菜鸟教程官网地址:${url}"
流程控制
条件分支
- if else模式
有else或者没有else都行
if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi # 终端命令提示符写法
# 或者脚本写法,把;用换行替换,一些关键字后的空格用换行缩进替换
if [ $(ps -ef | grep -c "ssh") -gt 1 ]
then
echo "true"
fi
- if else-if else模式
想象一个二叉树,不断进行条件判断进行延伸
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
循环
- for循环
array=(1 2 3 4 5)
for loop in ${array[*]}
do
echo "The value is: $loop"
done
#或者
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done
# 但是以下不行
for loop in (1 2 3 4 5)
do
echo "The value is: $loop"
done
- while循环
#!/bin/bash
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
- util循环
#!/bin/bash
a=0
until [ ! $a -lt 10 ]
do
echo $a
a=`expr $a + 1`
done
- 无限循环:三种方法
while :
do
command
done
#或者
while true
do
command
done
#或者
for (( ; ; ))
do
command
done