A Bash script is a plain text file which contains a series of commands.
Anything you can run normally on the command line can be put into a script
————https://ryanstutorials.net/bash-scripting-tutorial/bash-script.php
教程:一篇教会你写90%的shell脚本 - 知乎 (zhihu.com)
教程:ryanstutorials.net/bash-scripting-tutorial
教程:linuxconfig.org/bash-scripting-tutorial
Bash(Bourne Again SHell)是一种广泛使用的Unix shell和命令语言。
Bash(Bourne Again SHell)是一种命令语言,同时也是一个命令行界面。它是一个解释器,解释并执行输入到命令行的命令。
Bash 作为Linux和macOS的默认shell,Bash在自动化脚本、任务调度、系统管理等方面非常流行。
$( )
:【命令替换符】在shell script中执行shell命令的方式是通过$( )
参数创建一个subshell。用来重组命令行,先完成引号里的命令行,然后将其结果替换出来,再重组成新的命令行。
(Reference: The best way to execute a separate shell command inside of a Bash script is by creating a new subshell through the $( )
syntax. )
$STRING
:获取变量,使用一个定义过的变量
${#STRING}
:获取字符串长度,在${}
中使用#
获取长度
${STRING:1:4}
截取字符串
echo ${#name}; # 输出为4
;
分号,Shell 会按顺序执行每个命令,不论前一个命令的执行结果如何。
dirname $0 # 获取脚本文件所在的目录
$(cd $(dirname $0); pwd) #获取shell脚本所在目录的绝对路径
注释
Shell特殊变量:Shell $0, $#, $*, $@, $?, $$和命令行参数 - davygeek - 博客园 (cnblogs.com)
$0 # 当前脚本的文件名
$n # 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。
$# # 传递给脚本或函数的参数个数。
$* # 传递给脚本或函数的所有参数(将参数作为一个整体)。
$@ # 传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同(会将参数分开),下面将会讲到。
$? # 上个命令的退出状态,或函数的返回值。(大部分命令执行成功会返回 0,失败返回 1。)
$$ # 当前Shell的进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。
双引号(" ")包含时
"$*" 会将所有的参数作为整体,以"$1 $2 … $n"的形式输出所有参数;
"$@" 会将所有的参数各个分开,以"$1" "$2" … "$n" 的形式输出所有参数。
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
# 下面假定变量 a 为 10,变量 b 为 20
-eq # 相等 [ $a -eq $b ] 返回 false。
-ne # 不相等 [ $a -ne $b ] 返回 true。
-gt # 大于 [ $a -gt $b ] 返回 false。
-lt # 小于 [ $a -lt $b ] 返回 true。
-ge # 大于等于 [ $a -ge $b ] 返回 false。
-le # 小于等于 [ $a -le $b ] 返回 true。
# 假定变量 a 为 "abc",变量 b 为 "efg":
= # 相等 [ $a = $b ] 返回 false。
!= # 不相等 [ $a != $b ] 返回 true。
-z # 字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。
-n # 字符串长度是否为0,不为0返回 true。 [ -n "$a" ] 返回 true。
$ # 字符串是否为空,不为空返回 true。 [ $a ] 返回 true。
! :非运算,表达式为 true 则返回 false,否则返回 true。 [ ! false ] 返回 true。
-o :或运算,有一个表达式为 true 则返回 true。 [ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a :与运算,两个表达式都为 true 才返回 true。 [ $a -lt 20 -a $b -gt 100 ] 返回 false。
# 假定变量 a 为 10,变量 b 为 20:
&& # 逻辑的 AND
[[ $a -lt 100 && $b -gt 100 ]] # 返回 false
|| # 逻辑的 OR
[[ $a -lt 100 || $b -gt 100 ]] # 返回 true
# 只有在 && 左边的命令返回真(命令返回值 $? == 0),&& 右边的命令才会被执行。
command1 && command2 && command3 ...
# 只有在 || 左边的命令返回假(命令返回值 $? == 1),|| 右边的命令才会被执行。
command1 || command2
-b file :检测文件是否是块设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。
-c file :检测文件是否是字符设备文件,如果是,则返回 true。
-d file :检测文件是否是目录,如果是,则返回 true。
-f file :检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。
-g file :检测文件是否设置了 SGID 位,如果是,则返回 true。
-k file :检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。
-p file :检测文件是否是有名管道,如果是,则返回 true。
-u file :检测文件是否设置了 SUID 位,如果是,则返回 true。
-r file :检测文件是否可读,如果是,则返回 true。
-w file :检测文件是否可写,如果是,则返回 true。
-x file :检测文件是否可执行,如果是,则返回 true。
-s file :检测文件是否为空(文件大小是否大于0),不为空返回 true。
-e file :检测文件(包括目录)是否存在,如果是,则返回 true。
$( )
:【命令替换符】在shell script中执行shell命令的方式是通过$( )
参数创建一个subshell。用来重组命令行,先完成引号里的命令行,然后将其结果替换出来,再重组成新的命令行。
echo $(ls /etc)
$[ ]
: 加减乘除,不必添加空格$(( ))
:加减乘除等,不必添加空格[[ ]]
:中括号旁边和运算符两边必须添加空格 (字符串验证时,推荐使用)(())
: 中括号旁边和运算符两边必须添加空格 (数字验证时,推荐使用)变量类型
1、变量定义
创建普通变量: name="test" (=两边不可有空格)
变量重新赋值: name="new_test" (将原值覆盖)
创建局部变量: local name="test" (只可函数体中使用的,使用local修饰的变量在函数体外无法访问,并且local只能在函数体内使用)
创建只读变量: name="only_read" -> readonly name (使用readonly标识后的变量,不可被修改)
2、变量由结果赋值 $( )
#反引号`` 或者 $()
variable=`command`
variable=$(command) # 更推荐这种方式
#e.g
log=`cat log.txt`
log=$(cat log.txt)
3、变量引用
# $ :使用一个定义过的变量,只要在变量名前面加美元符号$即可
name="严长生"
echo $name
# ${ } :变量名外面的花括号{ }是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界 (推荐使用大括号版)
echo ${name}
双引号 vs. 单引号
BASH_VAR="Bash Script"
echo '$BASH_VAR "$BASH_VAR"'
# bash result
# $BASH_VAR "$BASH_VAR"
参考: shell的时间参数含义表示——%y%m%d/%H:%M:%S_uj_m的博客-CSDN博客_%y%m%d%h%m%s
loacl_time=$(data+"%Y%m%d %H:%M:%S")
4、unset 删除变量
unset name; (删除之后不可访问,删除不掉只读变量)
拼接字符串
name="this is"" my name";
name="this is my name";
name="this" is "my name"
# 以上等效
bash只支持一维数组,不支持多维数组
${array_name[@]}
数组所有元素
${#array_name[@]}
数组元素个数
This example declares an array with four elements.
#!/bin/bash
#Declare array with 4 elements
ARRAY=( 'Debian Linux' 'Redhat Linux' Ubuntu Linux )
# get number of elements in the array
ELEMENTS=${#ARRAY[@]}
# echo each element in array
# for loop
for (( i=0;i<$ELEMENTS;i++)); do
echo ${ARRAY[${i}]}
done
echo ${ARRAY[@]}
文件描述符:STDIN
、STDOUT
、STDERR
STDIN
):文件描述符为0。通常用于读取输入,如键盘输入。STDOUT
):文件描述符为1。用于输出数据,如屏幕显示。STDERR
):文件描述符为2。用于输出错误信息,通常也是显示在屏幕上,但可以被分开处理。文件描述符是一个在Unix和类Unix操作系统(如Linux)中用于访问和管理文件的抽象概念。
操作符:1>&2
:
command > file # 将输出重定向到 file (指定文件作为命令的输出设备)。
command < file # 将输入重定向到 file (指定文件作为命令的输入设备)。
command >> file # 将输出以追加的方式重定向到 file。
https://ryanstutorials.net/bash-scripting-tutorial/bash-input.php
introduction.sh
#!/bin/bash
# Ask the user for their name
echo Hello, who am I talking to?
read varname
echo It\'s nice to meet you $varname
bash ./introduction.sh
Hello, who am I talking to?
Ryan
It's nice to meet you Ryan
参数
# 从键盘输入
read firstStr secondStr
echo "第一个参数:${firstStr} 第二个参数:${secondStr}"
# 从键盘输入(-p)
read -p "请输入一段文字:" firstStr
# 从文件输入
read PID < $FILE
# 读文件
# cat 命令的输出作为read命令的输入,read读到的值放在line中
cat file| while read line
do
echo "$line"
done
exit 0
https://ryanstutorials.net/bash-scripting-tutorial/bash-arithmetic.php
expr item1 operator item2
# e.g a=$( expr 4 + 5 )
$(( expression ))
#e.g a=$(( 4 + 5 ))
${#variable}
# Length of a Variable
概览
https://ryanstutorials.net/bash-scripting-tutorial/bash-if-statements.php
sh的流程控制不可为空,即if或者else的大括号中无任何语句
if [ <some test> ];then
<commands>
fi
if [ <some test> ]
then
<commands>
fi
if [ <some test> ];then
<commands>
else
<other commands>
fi
# for in do done
for var in item1 item2 ... itemN do command1 command2 ... commandN done
# while do done (condition可以没有)
while condition do command done
until 循环执行一系列命令直至条件为 true 时停止。
until 循环与 while 循环在处理方式上刚好相反。
# until do done
until condition do command done
break
continue
Shell case in语句详解 (biancheng.net)
case <variable> in
<pattern 1>)
<commands>
;;
<pattern 2>)
<other commands>
;;
esac
概览
https://ryanstutorials.net/bash-scripting-tutorial/bash-loops.php
while [ <some test> ];do
<commands>
done
until [ <some test> ];do
<commands>
done
for var in <list>;do
<commands>
done
# e.g
for f in $( ls /var/ ); do echo $f; done
Variable Scope(By default a variable is global. )
Overriding Commands
https://ryanstutorials.net/bash-scripting-tutorial/bash-functions.php
function_name () {
<commands>
}
[ function ] funname() {
action;
[return int;]
}
return可存在也可不存在,如果不加return , 则默认最后一条语句的执行状态所为函数执行状态的返回值,(即 执行成功$?
为0,否则不为0)
function可存在也可不存在
1、函数定义及调用
# 定义
name() {
statements
[return value]
}
# 调用
name param1 param2 param3
2、传递参数
给定的参数以$1,$2,$3,…$n的形式访问,对应于函数名后参数的位置。
# e.g
count_num(){
result = $1+$2
echo "result is :$result"
}
count_num 5 6
3、变量的作用域
全局变量定义为可以在脚本内的任意位置访问的变量,而不管它的范围如何。
默认情况下,所有变量都定义为全局变量,即使它们在函数内部声明也是如此。还可以将变量创建为局部变量。可以使用local关键字在函数体内声明局部变量。
#!/bin/bash
v1='A'
v2='B'
my_var () {
local v1='C'
v2='D'
echo "Inside Function"
echo "v1 is $v1."
echo "v2 is $v2."
}
my_var
echo "v1 is $v1."
echo "v2 is $v2."
# v1 is A
# v2 is D
4、e.g
count_num(){
let "result = $1+$2" # or result=$(($1+$2))
echo "result is :$result"
}
count_num 5 6
# result is :11
printf 命令模仿 C 程序库(library)里的 printf() 程序。
和echo不一样,它不会在最后自动加上换行,需要写入命令中。
# e.g.
printf "Hello, world/n"
a='hello world'
echo "%s" $a # 结果 %s
printf "%s\n" $a # 结果 Hello, world
用于字符串/变量的输出
# 脚本内部变量
#! /bin/sh
time=$(date)
echo "time is ${time}"
# 等同于
echo `date`
输出到文件中
echo "time is `date`" > filename
echo "time is `date`" >> filename
\
:在脚本执行过程中还是当做一行一个语句执行,不同于enter直接换行
当我们在命令行前加上eval时,shell就会在执行命令之前扫描它两次.eval命令将首先会先扫描命令行进行所有的置换,然后再执行该命令。
foo=10
x=foo
y='$'$x
echo $y
# $foo
eval y='$'$x
echo $y
$10
1、shell脚本启动python执行.py脚本
# start_py.sh
conda activate py37
cd /usr/test/
python main.py
# 上述也可写为
/usr/local/bin/python3.7 /usr/test/main.py
# 执行
source start_py.sh
注意:执行shell脚本文件时,一定是source,不能是bash/sh,其原因是 source启动的shell脚本,是在父进程中继续运行的。而后面的3个启动方法,是新建子进程运行的。
2、shell脚本启动gunicorn,执行gunicorn命令
gunicorn+shell脚本+cron让项目自动发布 | 纸镜 (moshiwei.github.io)
#!/bin/bash
/home/mirror/djangoenv/bin/gunicorn --bind unix:/tmp/mirrorgo.top.socket blogproject.wsgi:application
如何传递和解析Linux Bash脚本参数和参数-CSDN博客
1、传递参数
$n
读取参数,n代表第几个参数
bash xx.sh param1 param2 ..
读取参数,n代表第几个参数, 有空格加引号"xx xx "
# !/bin/bash
# my.sh 脚本(读取参数)
echo $1 $2 $3
# 执行(传参)
bash my.sh hello1 hello2 "hello3 hello4"
# 输出
hello1 hello2 hello3 hello4
2、检测命令行参数
#!/bin/bash
if [ "$1" != "" ]; then
echo $1
else
echo "empty"
fi
3、赋值令行参数
#!/bin/bash
salute=$1
name=$2
echo $salute $name
4、getopt 处理参数
# abcd 分别代表四个选项,后面带有冒号的表示选项需要参数值。
GETOPTOUT=`getopt ab:c:d "$@"`
set -- $GETOPTOUT
while ...
# 执行
./proxychains4.sh -a -b t2 -c t3 -d
标准模板
ARGV=($(getopt -o 短选项1[:]短选项2[:]...[:]短选项n -l 长选项1,长选项2,...,长选项n -- "$@"))
eval set -- "$ARGV"
while true
do
case "$1" in
-短选项1|--长选项1)
process
shift
;;
-短选项2|--长选项2)
# 获取选项
opt = $2
process
shift 2
;;
... ...
-短选项3|--长选项3)
process
;;
--)
break
;;
esac
done
Linux提供了多种自动化工具,主要可以分为以下几类:
Bash语言 vs. Linux命令行
Bash语言是在Linux命令行界面中使用的一种脚本语言,具有丰富的编程特性,适用于复杂任务的自动化。
Linux命令行是与系统交互的接口,用于执行单个命令或简单的命令序列。
当你在Linux命令行中输入命令时,通常是Bash或类似shell(如Zsh或Fish)在解释和执行这些命令。因此,Linux命令行默认支持Bash语言,你可以在命令行中直接编写和执行Bash脚本或命令。在Bash脚本中,你可以直接使用Linux命令行中的所有命令。
在Unix和类Unix系统中,shell是一个命令行解释器,提供与操作系统交互的用户界面。
相关:
Linux自动化工具和技能:An Introduction to Linux Automation, Tools and Techniques - Linux Tutorials - Learn Linux Configuration