为什么输入指令没有获取快捷指令?

Shell是一个用C语言编写的程序,并且提供了专用命令语言。shell是linux系统必备工具(其它有些系统也有类似或相同的替代工具),在linux系统里打开终端或者使用ssh连接时都是使用命令语言作为交互支撑。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)
...
这里主要是bash为主,bash是免费通用的,并且是多数linux系统默认的shell工具。
以下是自己在编写shell脚本时使用和了解或收集到的一些基础,因为shell语法灵活和特殊性很难全部说到,这里仅以文字和简单的语句来概要下,可能少量语法存在兼容性问题,不足之处还请指出!
shell脚本可以辅助完成很多功能,通常把一些常用操作写成一个脚本方便后续使用。
shell脚本有一套简单灵活的命令语法规则,在使用时需要注意细节,否则容易掉沟里。脚本声明sehll脚本规定在有效代码前需要指定执行下面代码工具名,通过 #! 进行标记,后面追加写脚本位置,如果是bash工具,则:#!/bin/bash
注意: /bin/bash 是bash命令所在的目录
注意:脚本声明非必需,脚本声明必需在文件第一行有效,一般建议指明这样可以通用多种脚本调用方式也方便理解。
注释合理的注释方便理解,上面的命令标记也是注释,类似python2指定编码一样。
shell只有单行注释,没有专用的多行注释。单行注释以 # 作为起始,只要 # 不在有效命令或字符串内均会解析为注释,注释不会参与和影响脚本执行。例如:#注释要说明的内容写在这里
在实际使用中如果想多行注释一般建议通过多个单行注释拼接。执行脚本脚本运行需要有对应的解析执行工具,调用工具去解析执行shell脚本即为执行脚本(即使用bash工具执行指定的shell脚本)。脚本的启动方式会影响到脚本执行环境的差异。启动shell脚本也是一条命令,在脚本内也可以使用(但不要死循环启动)。
以执行脚本 test.sh 为例列举部分调用方式:bashbash(或sh)方式调用是创建一个新的执行环境执行shell脚本。
bash是shell脚本解析执行工具,是支持shell运行的平台。
执行命令:bash test.sh
sourcesource方式调用是在当前环境下执行shell脚本(即不创建新执行环境),共享当前环境全局变量和环境变量。source是shell内置命令。
注意:source如果没有指定传参(除脚本文件外的参数)会复制当前环境的传参数据(即当前脚本调用的参数),如果指定了任何其它参数则单独处理传参数据。
source语法:# 标准语法
source filename [arguments]
# 简写语法,注意:点与文件之间有空格
. filename [arguments]
执行命令:# 标准调用,共享脚本传参
source test.sh
# 简写调用,共享脚本传参
. test.sh
# 标准调用,不共享脚本传参
source test.sh test
./这种方式调用方式会先提取有效脚本声明语句(脚本声明就是指定当前文件下代码执行解析的命令位置,位置如果不对调用脚本时将会报错),找到解析执行工具命令,然后调用执行脚本(脚本文件必需有可执行权限)。通过这一特性我们可以指定其它语言脚本并且调用方式不变。
注意:如果没有脚本声明则默认按shell脚本执行。此调用方式是通过指定命令执行脚本,即在新执行环境运行。
创建并写文件:# 创建一个shell脚本
cat > test.sh <<EOF
#!/bin/bash
echo 'Hello, World!'
EOF
# 创建一个python脚本
cat > test.py <<EOF
#!/usr/bin/python
print("Hello, World!")
EOF
修改文件权限:chmod +x test.sh
chmod +x test.py
执行命令:# 调用shell脚本,输出Hello, World!
./test.sh
# 调用python脚本,输出Hello, World!
./test.py
调用命令调用命令是shell脚本最基本语句操作。一条完整的语句代码是由换行或分号隔开(并不是有换行或分号就代表语句结束),一条语句中可以包含一个及以上的命令执行。了解基本调用对编写脚本有很大帮助。
shell脚本有多种调用命令方式,一般有:反引号、$()、命令调用、nohup调用、直接调用、串联调用。
一般命令都有一些选项,选项定义时会有全名或简写,为方便选用部分命令允许简写选项合并到一起(比如:grep -orP 'bash' ./),而其它很多命令双不允许(比如:sed -r -i 's/1/2/')。不允许的要么解析选项错误要么只提取简写第一个字符,但标准分开写基本都支持,实际使用时对不熟悉的命令建议各选项分开。
注意:调用命令执行环境,主要有:新环境(空环境,即没有共享或复制其它环境中的变量或函数等数据)、当前环境(所有脚本共享变量或函数等数据)、子环境(复制上级环境已经生成的变量或函数等数据到新环境)。不同的执行环境变量信息是独立的且修改后互不影响(比如:变量修改、增加函数),当执行环境创建初始化完后(会自动复制环境变量,子环境会复制上级环境变量或函数),所有变量或函数不再受其它环境影响。
反引号这种调用方式主要用于提取命令结果,其调用的命令处理方式与bash一样。反引号在 子环境 中执行并将标准输出回传到上级环境并以字符串形式替换,由上级再次处理。
反引号内可以包含多个完整的执行命令,不同的命令可以使用 ; 或换行分隔,不可嵌套,比如:# 执行反引号内命令,并将命令内的标准输出再打印出来
echo -e `echo '012'; echo '123'
echo '345'
`
# 执行反引号内命令,并将命令内的标准输出内容赋值给变量SHELL_STR
SHELL_STR=`echo '012'`
反引号会将提取到的结果中的进行转义处理,也就是说如果结果中有转义的字符会再次转义,比如:echo `echo '\\'`
#打印输出 \
echo '\\'
#打印输出 \\
$()这种调用方式与反引号一样,但不会转义内部命令标准输出内容。
执行命令:echo $(echo '\\')
#打印输出 \\
SHELL_STR=$(echo '012') #把打印结果赋值给变量SHELL_STR
命令调用命令调用命令多用于拼装命令执行(比如:初始化变量,动态获取外部不同变量、复杂命令等)。执行命令:# 通过eval调用ps命令查看mysql服务是否开启
# eval是内置动态解析执行命令,命令后面的参数会全部进行语法再解析并执行,可以非常方法动态完成一些命令操作
# eval支持所有语法,主要用于在当前环境解析执行少量的动态代码
eval ps -C mysql
# 通过exec调用ps命令查看mysql服务是否开启
# exec自带少量参数命令,可以指定命令执行环境,此命令执行成功后会退出当前shell进程
exec ps -C mysql
# 通过xargs调用echo打印run.log文件内容
# xargs一般使用管道模式居多,但也可以指定文件参数传入后面的命令
xargs -a run.log echo
# 通过bash调用ps命令查看mysql服务是否开启
bash -c "ps -C mysql"
# 通过ssh登录127.0.0.1服务器,调用ps命令查看服务器里mysql服务是否开启
ssh root@127.0.0.1 "ps -C mysql"
# 通过bash调用ps命令查看mysql服务是否开启
# 这种用法一般推荐在脚本中使用,可以定义很多命令(如果执行一个shell脚本一样)
# 代码里的<<是重写向内容,具体查看下面介绍
bash <<CMD
# 这里好比一个shell脚本,可以写任何shell代码(但不能有结束符,即最后的CMD)
# 这里会在创建新的执行环境下运行代码
ps -C mysql
CMD
nohup调用nohup用于在系统后台不挂断地运行命令,退出终端不会影响程序的运行(很多用户态shell脚本或服务需要长期运行均使用nohup启动),nohup会创建一个新执行环境去调用后面的命令。
基本使用语法# command 是要执行的命令
# [argv ...] 是要执行的命令参数集
# & 是切换到后台执行(非必需)
# 注意:默认nohup命令会在当前目录下创建一个nohup.out文件用于保存要执行的命令所有标准输出内容(可以通过重定向修改保存的文件)
nohup command [argv ...] [&]
示例:# 后台执行ps命令,nohup会提示以下内容,ps所有标准输出内容都保存在当前目录下nohup.out文件中
# nohup: ignoring input and appending output to `nohup.out'
nohup ps aux
# 切换到后台执行nohup,nohup将在后台执行ps命令,ps所有标准输出内容都保存在当前目录下nohup.out文件
nohup ps aux&
# 后台执行ps命令,nohup会提示以下内容,ps所有标准输出内容都保存在/var/nohup.log文件中
# nohup: ignoring input and redirecting stderr to stdout
nohup ps aux >/var/nohup.log
直接调用直接调用最常用的调用方式是:命令 参数集 ...
直接调用命令名可以是变量替换,甚至整个命令都可以是变量替换。使用替换时不可使用双引号,否则会解析为一个整体。
示例:# find 是命令,后面的全部是参数集
find ./ -name '*.sh'
当一句代码会产生字符串值时未被接收给变量赋值或当作命令参数使用时就会被当作一个命令执行,一般所有字符串都需要有显示指定使用,否则就会被解析为命令执行(但需要注意的是字符串是个整体,即只能是命令名,如果包含命名名和参数将会被视为命名而导致命令找不到报错)。
示例:# 赋值操作
SHELL_TEMP_STR="find ./ -name '*.sh'" # 赋值操作,不会执行find命令
COMMAND_PARAM='-las' # 定义命令参数变量
ls $COMMAND_PARAM
#执行命令并指定变量参数
# 字符串命令执行
"find" ./ -name '*.sh'
# 定义的字符串未显示指定使用,将以命令代码执行
`echo "find ./ -name '*.sh'"`
# 定义的字符串未显示指定使用,将以把echo打印的内容当命令代码执行
'ls -a'
# 定义的字符串未显示指定使用,将以命令代码执行find命令
COMMAND_NAME='ls' # 定义命令变量
$COMMAND_NAME -las
# 执行命令
实际写shell脚本时需要格外注意上面这种执行方式。实际还有很多花样方式,这里就不全部列出。串联调用串联调用是在以上调用命令的基础上扩展的一种,这种调用方式可以把多个独立的语句串联为一条语句执行。串联调用是通过
、 && 、
、 & 运算符把多条语句连接在一起。串联调用可以混合使用运算符,同时也能使用括号(运算符是特殊字符在串联命令时要求必需使用空格隔开,分开便于阅读)。
注意:命令执行成功与失败以命令的退出或返回值来判断的,为0代表成功非0代表失败,可以通过 echo $? 查看
或串联调用。当前面的命令调用失败则调用后面的命令,以此依次向后面执行命令。这种串联调用不多见,多用于服务检测、应用判断等场景。
基本语法是:command1
command2
command3 ...
示例:# 如果sshd服务没有启动,则启动sshd服务
ps -C sshd
service sshd start
&&与串联调用。当前面的命令调用成功则调用后面的命令,以此依次向后面执行命令。这种串联调用比较常见,多用于命令按顺序同步执行成功场景(比如编译安装、服务关闭等)
基本语法是:command1 && command2 && command3 ...
示例:# 如果sshd服务已启动,则关闭sshd服务
ps -C sshd && service sshd stop
管道调用,通过管道符把多个串联执行命令连接在一起逐个调用,并且前面的命令标准输出内容会转发成后面命令的标准输入(如同管道一样,把前面的输出接入到后面的输入)。这种调用方式非常常见,多用于前面输入输出关联处理场景(比如处理字符串、文件内容提取或替换等)
基本语法是:command1
command2
command3 ...
示例:# 把当前目录下所有*.log文件内的shell替换为SHELL
find ./ -name '*.log'|xargs sed -i 's#shell#SHELL#g'
#去掉字符串内所有空格
STRING_TEST='a b c' ;
echo $STRING_TEST|sed -r 's/\s+//g'
#提取字符串内script
STRING_TEST='shell script' ;
echo $STRING_TEST|grep -oP 'script'
注意:管道符之后的命令是在子环境中执行命令(并将最后一个命令的退出值返回到上级环境的 $? 中)。
&切入后台运行调用。在一条完整语句或命令后面增加&后,这条语句或命令将切换到后台执行(即在另外一个子进程里执行这条语句或命令)。切换到后台执行后当前终端关掉将自动退出,如果不希望退出则需要配合nohup命令。
注意:&在shell脚本中类型是单运算符,即在&只会切换前面的命令或语句到后台不影响后面的命令或语句。
示例:# 在后台关闭sshd服务
service sshd stop&
# 在后台同时关闭sshd和nginx两个服务
service sshd stop& service sshd nginx&
! 调用! 是一个特殊命令,实际上不具备调用命令功能,它只是一个 $? 值取反处理命令(即 $? 值为0时 ! 命令退出1,反之退出0),但 ! 命令必需与其它语句组合成一个取反语句(可以 ! 命令多个并列使用),即 ! 命令不能单独使用。
特别说明下, ! 命令不具备调用命令的功能,也就是 ! 命令后面的命令语句不能用引号字符串代替,否则会解析为目录或可执行文件来处理。
! 命令在条件判断时非常实用,多用于if命令或串联命令调用中。需要注意:! 是一个命令,所以 ! 命令后面的需要留一个以上空格且只影响后面第一个语句。
示例:# 当在/var/log/messages文件中搜索不到shell字符时,输出0,否则输出1
! grep -qP 'shell' /var/log/messages && echo '不包含shell字符'
echo '包含shell字符'
# 判断sshd服务是否启动
# 注意:在用特殊命令[]或[[]]时!需要放在中括号内
[ ! -z "`ps aux|grep 'sshd'`" ] && echo 'sshd已经启动'
echo 'sshd未启动'
# 以下使用!命令会报错,因为!后面的命令是引号字符串形式
! "grep -qP 'shell' /var/log/messages";
# 命令将报错
命令替换命令替换是在执行语句前先把特殊语句替换为其内容后再运行这个语句,从而实现命令动态执行。
命令名和参数都可以使用命令替换。重定向、管道符、其它运算符、分号等特殊功能不可直接替换生效,需要借助解析命令再次解析执行(比如:eval)
双引号内的命令替换中能强制双引号内所有内容为一个整体(即使替换后存在双引号或其它特殊字符)。如果没有使用双引号的命令替换均以无引号形式表现,将对替换后的内容进行分段解析:空格分隔符(连续空格视一个,替换为命令名时前面的空格无效)、单双引号为字符串(必需有起始引号)、所有其它没分隔的文本为一个字符串(参数或命令名)。
注意:如果命令名是通过命令替换尽量不使用双引号,如果替换后有其它字符双引号会解析为个整体,导致命令名错误。比如:"find " ./ -name '*.sh'
替换语句主要有:变量替换、反引号替换、$()替换、$[]或$(())替换等。替换语句允许各种交叉嵌套组成复杂的动态语句。
注意:反引号不允许嵌套,可以包含其它替换语句;双引号嵌套只能包含在其它替换语句内;其它替换语句均支持嵌套。
变量替换所有变量使用语法(声明赋值除外)均可命令替换到语句中,如果替换时会混淆变量名则变量名需要使用大括号。反引号替换反引号会调用引号内的命令集并提取所有命令的标准输出内容(会对标准输出内容进行了转义处理),并将内容返回给上级环境中(以无引号字符串形式表现)。
注意:反引号内的命令是在子环境中运行。
$()替换$()替换实际上是()语句的提取语法,与反引号唯一区别是不会对标准输出内容进行转义处理。
注意:$()内的命令是在子环境中运行。
$[]或$(())替换$[]和$(())是shell提供的整数计算结果提取语法,功能或作用基本一样,替换完后将以无引号字符串形式表现。
注意:$[]和$(())内的命令是在当前环境中运行。如果需要切到子环境可以使用反引号或$()。
示例:# 变量替换,变量替换包含上面介绍的所有变量使用语法,这里仅示例部分
echo $PATH
echo ${PATH}
echo ${PATH:1:1}
# 反引号替换
echo `ls -las /`
# $()替换
echo $(ls -las /)
# $[]或$(())替换
echo $((5**5))
echo $[5**5]
变量shell变量不需要提前声明,除非是局部变量,在使用未定义变量是获取的值是空的。变量的命名一般使用大写加下划线方式,变量名必需是下划线或大小写字母开头后面可以是下划线、大小写字母、数值。
shell常用有三种数据类型:字符串、数值、数组。多数是以字符串为主。变量作用域shell变量作用域主要分为:全局变量、局部变量、局部特殊shell变量、环境变量。
shell脚本不同的调用方式会影响与上级环境的全局变量互通,具体可以了解下:执行脚本。全局变量全局变量作用域是在当前脚本执行环境内可见可修改(脚本执行环境参考:执行脚本)。并且在任何当前环境内任何地方创建或赋值均可被后面执行的命令使用。
例如:SHELL_TEST_VAL=0
#定义全局变量并赋值
局部变量局部变量只能用于函数内,当函数执行完后内部的局部变量全部释放。
例如:local SHELL_TEST_VAL=0
#定义局部变量并赋值
环境变量环境变量是通过export命令注册导入,注册后环境变量会在当前作用域内及当前作用域下调用的shell脚本内有效。可以理解环境变量生成后在当前环境下调用的所有执行环境脚本均会自动复制的特殊变量(不可反向复制到上级环境中)。如果需要修改可通过export命令再次注册导入修改。
注册示例:export SHELL_TEST_VAL1='123'
# 注册并赋值变量SHELL_TEST_VAL1
export SHELL_TEST_VAL2
# 注册变量SHELL_TEST_VAL2
内置变量内置变量是shell执行时自动创建一个局部环境变量(函数内也会更新部分内置变量),这些变量受bash版本影响。内置变量主要用于记录当前执行环境的各种信息提供给脚本使用,这些变量多数是可以修改的,可以通过 declare -p 命令查看。
注意:内置变量按普通变量使用即可,但尽量不要去修改。
下面列出一些常用内置变量提供参考:(实际还有很多)变量名
使用说明
BASH
当前执行的bash二进制程序目录,与脚本声明一致
BASH_VERSION
当前执行的bash二进制程序版本
USER
当前执行的bash二进制程序用户名,即运行用户
UID
当前执行的bash二进制程序用户ID
PWD
当前目录,和pwd命令一致
BASH_SOURCE
同执行环境加载的脚本文件名数组,第一个元素是当前文件名,此变量为复制品即各文件看到的不一样,主要针对加载命令 source ,函数调用时也会追加函数所有文件名
FUNCNAME
函数递归调用函数名数组,第一个是当前函数名,最后一个是main
BASH_ARGC
调用脚本的参数个数数组
BASH_ARGV
调用脚本的参数集数组
IFS
分隔符变量,默认换行符。影响识别分隔符的命令或语法
判断当前脚本是同执行环境调用#!/bin/bash
if [ $(basename "$0") = $(basename "${BASH_SOURCE[0]}") ];then
echo "不是相同环境执行"
else
echo '是相同环境执行'
fi
特殊变量特殊变量是脚本在执行过程中自动生成的一种特殊局部环境变量,这些变量只在脚本内相同执行环境下可见有效(同一个脚本$$、$0任何时刻不变,函数内部分变量除外)。当脚本运行后就会自动生成这些参数。
注意:特殊变量为防止篡改命名都是非正常命名规则,即不能通过常规语法修改,即使能修改也不建议修改,因为这类变量是shell解析执行器内部自动创建与赋值,自定义会带来不可预计的变化。
具体的变量表:参数名
使用说明
$*
脚本或函数所有参数集,从$1开始,各参数集中,如:"$1 $2 $3 ..."
$@
脚本或函数所有参数集,从$1开始,各参数分开,如:"$1" "$2" "$3" "..."
$#
传递到脚本或函数的参数个数
$$
当前脚本运行的进程ID号
$!
最后一个后台运行进程ID,需要切到后台运行,比如:& 或 nohup
$-
显示shell使用的当前选项,与set命令功能相同
$?
显示最近一个命令的退出或函数返回状态。0表示没有错误,其他任何值表明有错误。
$0
当前脚本或函数文件名
$n
n>0是,获取指定序号的脚本或函数参数值
${n}
与$n一个意思,当n>9时必需使用这种方式
$? 值是shell脚本内部自动修改,修改途径主要分三种情况:命令退出值(一个命令执行完成后退出值,默认是0即成功)、函数返回值(脚本可见域内函数return命令返回值,0即成功)、脚本退出值(脚本结束exit命令退出值,默认是0即成功)。默认是0。
$@ 是加引号列出数据,$* 是不加引号列出数。当作为参数传入时会有较大差异,例如:"$@" 会生成多个参数而 "$*" 只是一个参数。在数组中使用也是一样。
变量声明变量声明适用于所有作用域变量创建定义(特殊变量除外),内容可以是:字符串、数组等,可以限制:局部、只读。不同的变量声明对变量的使用有不同的变化,了解变量声明有利用灵活使用变量。全局变量全局变量在脚本执行的当前作用域内任何地方有效。全局变量是默认变量,可在以脚本内、函数内、命令内声明并赋值。
示例:BASH_VAL=0
#创建并赋值全局变量 BASH_VAL
BASH_VAL='0'
#创建并赋值全局变量 BASH_VAL
BASH_VAL="0"
#创建并赋值全局变量 BASH_VAL
BASH_VAL=(0 1)
#创建并赋值全局变量 BASH_VAL
局部变量局部变量是提供给脚本内定义的函数使用的临时变量。函数执行完后变量释放,且不影响与上层同名变量内容,上层变量可以是全局变量(初次调用函数)也可以是局部变量(函数内调用函数)且必需在当前执行环境中可见。局部变量使用local命令(local命令是function的子命令,即必需在function命令内使用)local BASH_VAL1 #创建局部变量不赋值
local BASH_VAL2=0 #创建局部变量并赋值
只读变量只读变量将变量修改为常量,即不允许修改也不允许手动删除(在设置为只读前变量必需指定值,否则后面将无法赋值)。只读变量使用readonly命令。readonly BASH_VAL1=0 #创建只读变量并赋初始值
BASH_VAL1=0
#创建一个变量并赋值
readonly BASH_VAL1
#将变量设置为只读
注意:只读变量和局部变量允许共存于同一个变量上。局部变量在函数调用内部可见(函数嵌套调用也可见),可以理解为函数调用完后自动删除这个变量。只读变量会监听变量赋值(也可以理解为赋值运算符重载),当变量赋值时就警告并终止赋值操作。
字符串字符串定义方式有:单引号、双引号、无引号、上面的反引号等。定义的符串必需显示指定使用,只定义没有显示指定为命令参数或赋值操作会解析为命令进行执行。单引号字符串单引号不会转义任何字符,也就是转义符 \ 在单引号内没有转义功能。在单引号字符串内定义是什么样的就是什么样的,所以单引号字符串不能出现不成对的单引号。
示例:STR_TEMP1=''
#创建一个空字符串变量STR_TEMP1
echo '\\'
#输出 \\
双引号字符串双引号字符串支持:转义、变量、嵌套反引号。
示例:STR_TEMP0=""
#创建一个空字符串变量STR_TEMP0
STR_TEMP1="${PATH}"
#创建一个字符串变量STR_TEMP1,并赋值环境变量PATH
STR_TEMP2="\\"
#创建一个字符串变量STR_TEMP2,并赋值 \
STR_TEMP3="test `echo 'ok'` ${STR_TEMP0} $STR_TEMP2"
#创建一个字符串变量STR_TEMP3,并赋值 test ok1 \
无引号字符串无引号字符串类似双引号字符串(特殊字符需要转义:|、&、空格、换行、;、括号、引号 等)。这个应该是命令调用格式的原因保留下来的一种特殊字符串语法,一般不推荐使用(容易出错和理解误差),尤其是有特殊字符时。
示例:STR_TEMP0=
#创建一个空字符串变量STR_TEMP0
STR_TEMP1=${PATH}
#创建一个字符串变量STR_TEMP1,并赋值环境变量PATH
STR_TEMP2=\\
#创建一个字符串变量STR_TEMP2,并赋值 \
STR_TEMP3=test`echo 'ok'`${STR_TEMP0}$STR_TEMP2
#创建一个字符串变量STR_TEMP3,并赋值 testok1\
字符串使用字符串有三种基本使用语法作用一样都是提取字符串内容。
示例及说明:# 打印字符串
# 标准写法,当变量未定义输出空
echo $STR_TEMP
# 打印字符串,这种写法比较适合字符串连接
# 标准写法,当变量未定义输出空
echo ${STR_TEMP}
# 连接字符串是隔开与变量名与其它字符以免造成变量名变动
echo "string: ${STR_TEMP}value"
# 打印字符串,这种写法适合函数内或使用未知定义变量时
# 询问写法,当变量STR_TEMP不存在时返回123
echo ${STR_TEMP-'123'}
字符串连接字符串连接很简单,支持多个字符串并排连接(并排处不能有空格或换行隔开),并排的字符串形式有:字符串变量、双引号字符串、单引号字符串、反引号字符串,它们之间可以任意组合。
示例:STR_TEMP="11 $PATH"'22'`echo "ok"`$PATH
#创建一个空字符串变量STR_TEMP,并赋值
字符串提取字符串提取有多种便捷语法,包括下面数据提取中介绍的,除了这些方式也可以通过命令来提取。字符串还提供了匹配提取语法如下表:语法
使用说明
${#name}
获取字符串name长度,不是字节数,是字符个数
${name#*chars}
从字符串name第一次出现 chars 的位置开始,截取 chars 右边的所有字符
${name##*chars}
从字符串name最后一次出现 chars 的位置开始,截取 chars 右边的所有字符
${name%chars*}
从字符串name最后一次出现 chars 的位置开始,截取 chars 左边的所有字符
${name%%chars*}
从字符串name第一次出现 chars 的位置开始,截取 chars 左边的所有字符
${name/pattern/pattern}
将字符串name的第一个匹配的pattern替换为另一个pattern
${name//pattern/pattern}
将字符串name的所有匹配的pattern替换为另一个pattern
注意:字符串替换的pattern是模式匹配并非正则,模式匹配的说明参考下面介绍。
示例:STRING_VAL=" This is a shell script。"
echo ${#STRING_VAL}
#输出 24
echo ${STRING_VAL#*a}
#输出shell script。
echo ${STRING_VAL##*a}
#输出shell script。
echo ${STRING_VAL%a*}
#输出This is
echo ${STRING_VAL%%a*}
#输出This is
echo ${STRING_VAL/This/}
#输出is a shell script。
echo ${STRING_VAL//s/S}
#输出ThiS iS a Shell Script。
# 以下提取方式在下面的数据提取中会介绍更多
echo ${STRING_VAL:10}
#从序号10开始截取字符串,输出shell script。
echo ${STRING_VAL-'empty'}
#如果字符串STRING_VAL不存在则返回empty,输出 This is a shell script。
echo ${STRING_VAL:11:5}
#从序号11开始截取5个字符串,输出shell
echo ${STRING_VAL:0-13}
#如果开始值为负数则从右向左定位再取,输出shell script。
echo ${STRING_VAL:0-13:5}
#如果开始值为负数则从右向左定位再取,输出shell script。
常用命令提取:(以上面的变量STRING_VAL为例)
sed命令去掉首尾空格STRING_VAL=`echo $STRING_VAL|sed -r 's/(^\s+)|(\s+$)//g'`
grep命令提取is之前的内容STRING_VAL=`echo $STRING_VAL|grep -oP '.*?is'`
awk命令提取第四段内容 shellSTRING_VAL=`echo $STRING_VAL|awk '{print $4}'`
数值shell本身没有数值处理功能,计算需要依赖命令:awk、expr、bc 等,但shell提供了另一种内置整数计算语法(具体参考下面双小括号使用)。造成这种原因应该是命令调用解析字符串的关系。数值计算在shell脚本中时常有使用到,一般小数据使用expr来计算,高精度计算使用bc。
计算示例:expr 2 '+' 2
#输出4
echo '2 + 2'|bc
#输出4
expr
命令格式:expr ARG1 oper ARG2
ARG1 和 ARG2是两个运算数(或字符串),oper是运算符(|、&、<、<=、=、>、>=、+、-、*、/、%、:)
由于运算符有些是特殊符号(比如:>、*),所以运算符号这个参数建议都使用单或双引号括起来以免语法报错。
运算符 : 是字符串包含判断计算(右边的字符是否在左边内存在)。
bc
是一个高精计算工具,提供的是以文件为参数去计算文件内的计算表达式。
因为参数是文件,所有一般使用管道符
进行快捷表达式计算。
数组数组可以方便收集配置或者临时缓存集合数据很实用,数组的使用也很简单。数组的 [] 非常灵活可用:@或*、数值、基本运算表达式、字符串值或表达式等,只要保证最终内容是数组要求的即可。唯一不足的是数组只有一维,如果需要使用多维则需要多个数组组合使用,不怎么方便。
以下均为数组名array_name为例做示范。
shell数组声明赋值三种语法:# 直接创建数组变量并赋值所有选项
# 注意:空格代表后面是下一个数组元素,
# 如果数组元素内有空格则需要使用单或双引号括起来以免被拆分
# 只有一个元素时不可使用这种语法,具体原因可参考下面的小括号命令组
array_name=(value1 value2 ... valuen)
# 定义一个空数组
array_name=()
# 定义有单值数组
array_name=(1)
# 定义有多值数组
array_name=(a b '=')
# 创建数组并逐个赋值
array_name[0]=value1
array_name[1]=value2
# 数组追加赋值,数组必需先定义否则存在兼容问题
# 注意:${#array_name[@]}是获取数组array_name的长度,长度是从0开始,存入序号也是从0开始,刚好错开一个能一直追加数组元素数据
array_name[${#array_name[@]}]=value1
array_name[${#array_name[@]}]=value2
数组使用语法:# 打印数组第一个元素数据
# 数组序号是以0开始
echo ${array_name[0]}
# 判断取值,当序号为3的元素不存在时返回default,其它判断取值使用一样
echo ${array_name[3]-'default'}
# 打印数组所有数据,所有使用这种语法的地方均是先转成字符串再应用到命令中(即命令替换)
# * 和 @ 类似上面的局部特殊shell变量,作用类似。两种语法功能一样,但一般使用@
echo ${array_name[*]}
echo ${array_name[@]}
# 打印数据元素个数
# 以下两种语法都可以获取到相同的数组长度
echo ${#array_name[*]}
echo ${#array_name[@]}
数组拼接# 把数组 array_name1 和 array_name2 合并为一个数组 array_name3
# 如果有很多数组参与合并直接在后面追加即可,但每个合并数组需要使用空格分开
# 注意:这种拼接各数组的每个元素不能有空格,否则会导致元素拆分
array_name3=(${array_name1[@]} ${array_name2[@]})
数组截取# 把数组 array_name1 从第序号第二个开始所有元素赋值给数组array_name2
array_name2=${array_name1[@]:2}
# 把数组 array_name1 从第序号第二个开始截取3个赋值给数组array_name2
array_name2=${array_name1[@]:2:3}
删除数组或元素# 删除数组内序号为2的元素
# 这个元素删除后不影响数组其它元素序号,即这个序号再次获取是空的
unset ARRAY_TESTS[2]
# 删除整个数组,删除后就是一个空数组
unset ARRAY_TESTS
关联数组关联数据只有在新版中存在,通过命令declare创建,与上面的数据主要区别在于序号不再是数值而是字符串键名。仅以创建关联数组为例说明下:# 创建数组再赋值
declare -A array_name
array_name["key1"]="value1"
array_name["key2"]="value2"
#创建数组并赋值
declare -A array_name=(["key1"]="value1" ["key2"]="value2")
数据提取shell提供了一些便捷数据提取语法,在以上各种变量中非常实用。提取语法
特殊变量
数组
字符串或环境变量
使用说明
${name:start}
${*:start} 或 ${@:start}
${array_name[*]:start} 或 ${array_name[@]:start}
${string_name:start}
获取数据从start开始的所有数据
${name:start:length}
${*:start:length} 或 ${@:start:length}
${array_name[*]:start:length} 或 ${array_name[@]:start:length}
${string_name:start:length}
获取数据从start开始length个数据
${name-default}
${n-default}
${array_name[n]-default}
${string_name-default}
当$name存在时返回$name,否则返回default;
${name:-default}
${n:-default}
${array_name[n]:-default}
${string_name:-default}
当$name存在且非空时返回$name,否则返回default
${name+default}
${n+default}
${array_name[n]+default}
${string_name+default}
当$name不存在时返回空,否则返回default
${name:+default}
${n:+default}
${array_name[n]:+default}
${string_name:+default}
当$name为空时返回空,否则返回default
${name=default}
${n=default}
${array_name[n]=default}
${string_name=default}
当$name不存在时返回default,否则返回$name
${name:=default}
${n:=default}
${array_name[n]:=default}
${string_name:=default}
当$name存在且非空时返回$name,否则返回default
${name?default}
${n?default}
${array_name[n]?default}
${string_name?default}
当$name存在时返回$name,否则将default输出到stderr并产生错误提示
${name:?default}
${n:?default}
${array_name[n]:?default}
${string_name:?default}
当$name存在且非空时返回$name,否则将default输出到stderr并产生错误提示
${name:start}、 ${name:start:length} 是截取部分数据语法。其中name可是数据名(脚本或函数参数集符、数组集表达式、字符串名),start和length是数值也可以是算术表达式。
${name-default}、${name:-default}、${name+default}、${name:+default}、${name=default}、${name:=default}、${name?default}、${name:?default} 语法都是条件取值语法。其中name可是(脚本或函数参数序号、数组元素表达式、字符串名),default是默认字符串值。
注意:变量名及其它参数可以是字符串的各种标准语法
示例:(以下代码脚本名为test.sh,调用命令:bash test.sh '' 2 3 )# 特殊shell变量特殊取值处理,其它相关用法一样,仅仅需要注意用意。
# 取一段参数集
echo ${*: 2}
# 输出2 3
echo ${@: 3:1}
# 输出3
# 判断某个参数存在或空再取对应值
echo ${1-2}
# 输出空
echo ${1:-2}
# 输出2
获取变量当不知道当前环境有哪些可使用变量时,通过命令获取变量来的会比较快,尤其在编写自动调用脚本时。获取所有环境变量环境变量是通过export命令创建的。env
#输出所有环境变量及其赋值表达式
注意:env命令功能很多,不仅仅是打印变量信息,有兴趣的单独了解下。
获取所有环境变量和用户变量declare命令支持环境变量和用户变量的声明与删除,同时也可以输出这些变量信息。
declare命令主要参数说明:参数
说明
-a [数组声明语句]
创建、打印索引数组
-A [数组声明语句]
创建、打印关联数组
-f [函数体语句]
打印指定或所有函数体
-F [函数名]
打印指定或所有可见函数名
-r [变量声明语句]
创建、打印只读变量
[+-]i [变量声明语句]
创建、删除、打印整数变量
[+-]x [变量声明语句]
创建、删除、打印环境变量
-p [变量名]
打印指定或所有(含环境)变量,所有变量携带declare命令前缀
-g
打印函数体或(含环境)变量,所有变量不携带declare命令前缀
注意:declare命令变量操作参数前缀 + 表示要删除 - 表示要创建,删除或创建时后面不指定语句将作打印操作。declare命令功能还有其它功能暂未详情说明,有兴趣的单独了解下。
常规示例:declare -a #输出所有可见索引数组及其赋值表达式
declare -a ARRAY_VALS='(1 2 3 4)' #创建数组
declare -p #输出所有可见变量及其赋值表达式
declare -g #输出所有可见变量或函数及其赋值表达式
括号()、[]、{}的作用shell中支持小、中、大括号语法,灵活使用这些语法可以很方便完成一些特殊操作。小括号:()单小括号小括号在前面数组声明和命令调用中提到过两种语法。小括号可以内部将命令集在子环境中运行(可以嵌套使用)。小括号内的命令或语法使用分号隔开(就相当于一个内置shell脚本块,支持shell脚本的所有语法)。如果需要提取小括号内的标准输出则在小括号左边增加个$或者使用反引号。
小括号命令组语法:# 单小括号基本语法
(command1; command2; command3; ...)
# 执行小括号内代码段,并提取标准输出内容赋值给变量STRING_TEST语法
STRING_TEST=$(command1; command2; command3; ...)
# 执行小括号内代码段,并提取标准输出内容赋值给变量STRING_TEST语法
# 不推荐使用,因为反引号也是一种内置shell脚本块且会转义标准输出内容
STRING_TEST=`(command1; command2; command3; ...)`
示例:STRING_TEST='123'
# 执行内置代码块
(STRING_TEST='456'; echo $STRING_TEST) # 输出 456
echo $STRING_TEST
# 输出 123
# 执行内置代码块
STRING_TEST=$(STRING_TEST='456'; echo $STRING_TEST) # 标准输出赋值给变量STRING_TEST
echo $STRING_TEST
# 输出 456
双小括号双小括号是shell内置高效整数运算命令,支持逻辑运算、位运算、算术运算、比较运算、赋值运算、自增减运算(使用可以参考下C语言对应的运算符和优先级),表达式可以是一连串复杂的计算公式和赋值操作,同时也允许嵌套小括号。
运算数不允许有非数值参与计算(即标准数值且不能使用引号),运算符也不允许使用引号(除赋值运算外其它运算符建议与运算数之间增加一个以上空格分开),可以嵌套反引号(只要命令输出值满足表达式结构即可),赋值运算左边允许是变量名。
注意:双小括号内的表达式是在当前运行环境下执行。在双括号前面增加$即为提取返回值语法(将运行在子环境中)。
双小括号命令信息:# 通过help命令查看双小括号命令信息
help '(('
# 整数运算命令语法,一般这种语法用于if判断居多
((expression))
# 提取整数运算语法
echo $((expression))
示例:STRING_TEST=2
echo $((STRING_TEST=5+5))
# 输出10
echo $STRING_TEST
# 输出10
STRING_TEST1=`echo $((STRING_TEST=15+15))`
# 输出30,且不影响当前环境
echo $STRING_TEST
# 输出10
echo $STRING_TEST1 # 输出30
((`echo STRING_TEST`=5*5)) # 内部嵌套反引号参数表达式计算,注意反引号也可以用来生成运算符
echo $STRING_TEST
# 输出25
中括号:[]单中括号中括号在前面数组使用中已经介绍部分语法。单中括号还可以当test命令使用,中括号内部左右两边需要留一个及以上空格否则不会以test命令执行(单中括号一般用在if条件判断居多)。可以理解单中括号是test命令的简写语法。
说明:单中括号命令是按test命令来执行,使用时需要参考test命令参数用法。使用时将test参数放置到中括号内即可。单中括号内部分特殊条件符号需要使用转义或引号处理否则命令失败,如:>
test命令是shell内置字符串运算命令,一切运算处理都是按字符串处理,即使在进行数字比较时,这块需要额外注意,因为在有符号数值比较时会有差异。
命令信息# 通过help命令查看单中括号命令信息
# 注意:这条命令会把双中括号的信息也介绍掉
help '['
# 查看test命令信息
help test
示例:[ -n "1" ]; echo $? # 字符串不为空,输出0
[ ! -z "1" ]; echo $? # 字符串不为空,输出0
[ -z "" ]; echo $? # 字符串为空,输出0
[ -e "/var/log/messages" ]; echo $? # /var/log/messages文件存在,输出0
[ -d "/var/log" ]; echo $? # /var/log目录存在,输出0
[ -5 '>' -2 ]; echo $?
# 字符串数值比较输出1,注意:运算符号最好使用引号或转义符号处理
# 中括号内部的字符串或参数项也可以使用其它语法生成拼接成更复杂灵活的语句
[ '-n' "`find ./ -name '*.log'`" ]; echo $? # 当前目录下是否存在*.log文件,有输出0,无输出1
注意:多个命令并排需要使用分号隔开。单中括号以test命令使用就会将命令退出值写入$?特殊变量中。
$[]单中括号$[]语法与双小括号功能一样,也是提供内置整数整数运算,唯一不同的是$[]不能去掉前面的$也就是$[]返回一个字符串需要按字符串的原则来处理否则会再次再命令解析并执行。所以通常认为双小括号运算要比$[]运算快,而$[]好比$(())的简写语法。双中括号双中括号就相当于test命令增强版(去掉了test命令的-o和-a两个参数,即或和与),增加模式匹配,内部语句将子环境下运行。双中括号命令有模式匹配,是通过运算符 == 或 != 时右侧字符串作为模式匹配处理(具体语法查看下面的模式匹配介绍 ),使用运算符 =~ 时右侧字符串作为正则表达匹配。同时支持
和 && 运算连接多个test命令处理。
注意:双括号命令会严格按运算标准去解析内部参数并以空格为分隔符,甚至有些特殊符号不需要转义也会解析为参数而不是解析成其它功能,当然有特殊字符的字符串最好使用引号括起来容易识别且不易出错,模式匹配串或正则表达式不需要引号(如果特殊符号会影响到语法则需要使用转义符号处理),双中括号内部两侧需要留一个及以上空格否则不会以双中括号命令执行。
双中括号的命令信息:# 通过help命令查看双中括号命令信息,注意结合test命令信息使用
help '[['
示例:[[ -5 > -2 ]]; echo $?
# 字符串数值比较输出1,注意:双中括号不需要处理运算符号
[[ ! -n `find ./ -name *.log` ]]; echo $? # 当前目录不存在*.log文件,输出0或1
[[ 'shell script' == shell* ]];echo $? # 左边字符串包含模式匹配串 shell* ,输出0
[[ 'shell script' =~ [a-z]+ ]];echo $? # 左边字符串符合正则表达式 [\w\s]+ ,输出0
[[ 'shell script' == shell* && 'shell script' =~ [a-z]+ ]];echo $? # 两个字符串运命令处理通过 ,输出0
注意:模式匹配必需右全匹配左边多余的使用通配符*,正则表达式是按正则规则来处理的,当没有限定起止符时就是模糊匹配。正则表达式使用时注意下语法,具体可了解下面正则表达式的介绍。
大括号:{}大括号没有单双之分且${}语法是变量专用。大括号是一个在当前环境执行的块命令(类似单小括号,区别在于执行环境)。大括号内两侧需要留一个及以上空格否则不会以大括号命令执行,一般大括号用于一段代码重定向或运算选项执行。
大括号命令有点类似匿名函数。
双小括号命令信息:# 通过help命令查看 {} 命令信息
help '{'
# 通常语法
{ command; ... }
示例:{ echo 'ok'; echo 'error' >&2; } 2> /dev/null # 屏蔽错误输出,实际输出 ok
流程控制shell脚本有多种流程控制命令,基本上每个流程控制命令是由多个命令组成,在使用时以换行或分号隔开,且允许嵌套。条件控制当需要按条件选择执行区域代码时条件控制是必经之路,条件控制多样化,但总体来说需要使用到判断。shell条件判断提供了多种方式,包括前面串联命令调用提到的
和&&运算符,还有下面要说的条件判断命令。ifif判断非常灵活,它是通过提取if至then命令间最后一个命令或函数的退出或返回值来判断(即$?的值来判断,0代表true,1~255代表false)。if由5个命令组成,其中elif、else、then、fi是依赖性子命令(这4个命令必需在if之后且有对应层关系和顺序)。
if命令信息:# 通过help命令查看if命令信息
help if
# 通常语法
if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
注意:if命令中每个子命令间允许多个命令分开执行,也就是可不使用串联调用命令的方式(在if或elif命令到then命令间会自动提取最后一个命令或函数的退出或返回值来判断)
示例:# 启动sshd服务处理
if ps aux|grep 'sshd';then
echo 'sshd ok';
else
service sshd start
fi
# 简单整数计算脚本处理
# 注意:因为$1参数可能不存在,所以需要使用双引号,不然参数代入后[]命令将丢失数据为[ -n ]导致命令错误
if [ -z "$1" ];then
echo '参数未传入!';
elif [ "$1" = 'help' ];then
echo '这个是一个简单的整数计算脚本,参数中请输入标准的整数计算公式即可得出结果。';
elif [[ "$1" =~ [0-9]+[\+\*/-][0-9]+([\+\*/-][0-9]+)* ]];then
echo '计算结果是:'
echo $(($1));
else
echo $1'未知参数!';
fi
casecase命令类似其它开发语言的switch。case支持使用模式匹配(模式匹配参考下面的介绍),且支持并列可选命令
,非常方便。可选命令
前后允许空格且这些格式不会进入模式匹配(如果需要进入则需要增加转义)。
case命令信息:# 通过help命令查看case命令信息
help case
# 通常语法
case WORD in [PATTERN [
PATTERN]...) COMMANDS ;;]... esac
语法说明:WORD 是要匹配的任何字符串,比如:有引号、无引号(空格或特殊符号要转义)、反引号等。
PATTERN 是要匹配的模式匹配或字符串,并且可以通过可选命令并列存在。
) 是匹配模式与匹配成功执行命令段的分隔符
;;
是匹配成功执行命令段结束符
注意:case语法有些特殊(特别是匹配区块处理)。case模式匹配功能强大主要支持:有引号字符串相等匹配、其它形式字符串是模式匹配(主要是:无引号、反引号、其它命令形式等。模式匹配语法参考下面的模式匹配介绍)、可选命令(允许多种语法混合)。
示例:case 'test.py' in
*.js|'*.h5')
echo '前端H5';
;;
*.php
"*.java"
*.py)
echo '后端';
;;
*.sh|$?)
echo 'shell脚本';
;;
*)
echo '其它';
;;
esac
# 输出:
#后端
case 匹配原则是从上到下逐个节点模式匹配,匹配到后就停止向下再匹配。如果需要增加 *) 匹配则必需放到最后否则会提前结束匹配。
循环控制shell提供了三种循环命令:for、while、until。这三种请求语法多样且功能多,基本上每个循环命令都有多种用法,熟悉这些用法将会大提升编写效率。
注意:循环使用不当容易造成死循环,要保证循环能正常退出,除非你需要死循环。
forfor命令主要有两种用法:C语言风格for循环、Python风格for in循环。其中Python风格语法灵活,且提供了很多便捷用法。
for命令信息:# 通过help命令查看for命令信息
help for
# 通常语法
# C语言风格for循环
for ((exp1; exp2; exp3)); do COMMANDS; done
# Python风格for in循环
for NAME [in WORDS ... ] ; do COMMANDS; done
C语言风格for循环exp1、exp2、exp3分别是三个算术表达式:初始赋值、循环判断、循环变化。
exp1 只在循环进入时执行,exp2是循环体进入判断,exp3是单次循环结束后调用
单次循环结束后再判断exp2,成功进入循环体,直到exp2条件不成立结束循环
exp1、exp2、exp3这三个表达式是可选表达式,如果不写可留空但中间的两个分隔分号必需有。exp2不指定则是死循环
Python风格for in循环[in WORDS ... ]是要循环的字符串(可以是任何字符串及形式),以空格分隔(可以使用引号或转义使循环字符包含空格)
[in WORDS ... ]是可选的,当不指定则默认类似循环shell环境变量$@
[in WORDS ... ]可以是范围值语句{start..end},类似正则的字符范围
NAME 是每次进入循环体前写入当前所在循环字符串值的变量名,在循环体内可直接使用。
示例:# C语言风格for循环
for ((NUM=0; NUM<2; NUM++)); do
echo $NUM;
done;
# 输出:
#0
#1
# Python风格for in循环
# 循环字符串
SHOW_STR='456'
for ITEM in abc $SHOW_STR `echo 'shell'` $((5+6)) "& &"; do
echo $ITEM;
done;
# 输出:
#abc
#456
#shell
#11
#& &
# 循环0-3和a到c,这里可以指定单独一个范围
for ITEM in {1..3} {a..c}; do
echo $ITEM;
done;
# 输出:
#1
#2
#3
#a
#b
#c
# 循环数组变量
# for in循环数组时需要注意数组中的元素不能有空格,因为${ARRAY_VALS[@]}是把数组转为字符串使用空格隔开且每个元素没有使用引号,导致元素中的空格会拆分成多个元素。
ARRAY_VALS=(123 456 789)
for ITEM in ${ARRAY_VALS[@]}; do
echo $ITEM;
done;
# 输出:
#123
#456
#789
# 循环$@变量
for ITEM in $@; do
echo $ITEM;
done;
{start..end}是一个生成命令,这个命令可以指定范围的数值(范围是正负2的15次方)或字母(26个大小写字母)集并以空格分开,在for循环中非常实用。命令中{}和..是语法关键字,start和end是范围首尾数字或字母(首尾指定是生成的区间且允许正和逆向生成,比如:数值从小到大或从大到小、字母从a到z或从z到a均可以)。
生成命令中不允许有空格分开,即{ 1..5}、{1..5 }、{1.. 5}、{ 1..5 }等都是错误语法将按无符号字符串处理。
{start..end}生成命令还有一个强大特性即交叉生成,命令前后如果有相连字符串或{start..end}生成命令就会生成交叉或重复内容。
示例:# 交叉生成
echo {z..r}{1..5}
# 输出
#z1 z2 z3 z4 z5 y1 y2 y3 y4 y5 x1 x2 x3 x4 x5 w1 w2 w3 w4 w5 v1 v2 v3 v4 v5 u1 u2 u3 u4 u5 t1 t2 t3 t4 t5 s1 s2 s3 s4 s5 r1 r2 r3 r4 r5
# 顺序生成
echo shell-{1..5}.sh
# 输出
#shell-1.sh shell-2.sh shell-3.sh shell-4.sh shell-5.sh
注意:交叉生成的数量需要提前算好,过大的生成数量会很慢,尤其多级交叉生成。
whilewhile命令通过循环调用指定命令并判断命令调用是否成功,成功就执行循环体内语句,失败就结束循环处理跳出整个while命令体。while命令信息:# 通过help命令查看while命令信息
help while
# 通常语法
while COMMANDS; do COMMANDS; done
示例:# 一般固定次数循环语法
NUM=3
while ((NUM-- > 0));do
echo $NUM
done
#输出:
#2
#1
#0
# 结合read命令读取文件
# 循环体在子环境中运行
SHOW_STR=''
echo -e "123\n456"|while read -r ITEM;do
SHOW_STR=$SHOW_STR$ITEM"\n"
done
echo -e $SHOW_STR
#这里输出是空
# 循环体在当前环境中运行
SHOW_STR=''
while read -r ITEM;do
SHOW_STR=$SHOW_STR$ITEM"\n"
done <<EOF
123
456
EOF
echo -e $SHOW_STR
#输出:
#123
#456
注意:read命令功能很多,可通过命令help read查看具体说明,一般与while结合读取文件非常方便。
read在循环体内调用read读取标准输入,内部read命令可能会出现无法正常使用的情况,使用前需要额外注意。
untiluntil命令与while命令语法和功能一样,唯一区别在于until判断是取反,即whil中循环成立在until中循环不成立。一般until命令使用很少,使用while就能代替。until主要用于失败检测时会比while简单且高效,因为放在while中需要取反命令再处理,不过性能影响不会太明显。
until命令信息:# 通过help命令查看until命令信息
help until
# 通常语法
until COMMANDS; do COMMANDS; done
示例:NUM=0
until ((NUM++ > 2));do
echo $NUM
done
#输出:
#1
#2
#3
注意:while的用法在until中一样可以使用,唯一需要注意的是until是取失败状态的。
循环跳出循环的过程中如果需要跳出循环或进入下一次循环建议使用循环跳出命令,循环跳出命令可以非常方便跳出循环并且可以指定跳出循环层级(多层嵌套循环时),多层时从最近跳出命令开始计数,默认是一层。
循环跳出命令适用前面三个循环命令。
breakbreak是跳出指定层数整个循环命令。
break命令信息:# 通过help命令查看break命令信息
help break
# 通常语法
break [n]
示例:ARRAY_VALS=(123 456 789 abc)
for ITEM in ${ARRAY_VALS[@]};do
if [ ${ARRAY_VALS[2]} = $ITEM ];then
break;
else
echo $ITEM
fi
done
#输出:
#123
#456
continuecontinue进入指定层数循环的下一次循环,即跳到指定层循环的单次循环结束位置。
continue命令信息:# 通过help命令查看continue命令信息
help continue
# 通常语法
continue [n]
示例:ARRAY_VALS=(123 456 789 abc)
for ITEM in ${ARRAY_VALS[@]};do
if [ ${ARRAY_VALS[2]} = $ITEM ];then
continue;
else
echo $ITEM
fi
done
#输出:
#123
#456
#abc
参数传递在shell脚本中的所有代码都可以理解为不同命令的调用,多数命令必需结合传入的参数进行工作,受不同命令或语法影响参数传递形式多样化。可以理解shell脚本就是各种命令和对应参数的组合。
参数传递形式有:无引号字符串、有引号字符串、变量、反引号、$()、$(())、$[]、管道符、标准输入、正则表达式、模式匹配串、及组合嵌套等。命令在调用前会依次解析后面所有对应参数(带命令的参数执行命令并提取,变量参数直接取值等),最终将所有参数解析成字符串并替换对应的表达式(有引号字符串解析替换后依然保留引号),然后传递给命令进行执行处理。
熟悉各种命令的参数语法是编写shell脚本的基础,尤其是shell内置命令。
特殊参数当一个命令的参数有特殊符号影响语法解析时就必需使用转义符。一般当命令语法报错时就需要考虑是否需要增加转义。转义命令可以将空格或换行转义掉,比如:参数有换行或串联调用命令分段换行。
示例:#!/bin/bash
echo 'shell' && \
echo 'ok'
# 输出:
#shell
#ok
注意:当一个命令的参数必需有时,对传入的各种形式的参数需要保证其的值不是空,因为空会在命令执行时参数替换为空格导致命令参数无法获取,这个时候就需要使用引号括起来(引号内部虽空但命令解析可以获取到一个空参数,而不是无参数),特殊参数除外(比如:正则表达式或模式匹配串)。
函数函数是shell脚本中生成自定义局部命令的命令,函数内是编写好局部命令的shell脚本代码,函数名即是命令名可按命令调用方式调用,调用后将执行函数内的代码。函数定义是通过function命令,该命令会生成局部命令且只在当前执行或子环境下有效(函数调用前必需先定义,否则无法调用,函数的实际执行环境受调用方式影响),脚本结束后立即释放函数。
注意:由于函数体是一个局部命令体,所以函数内部会自动创建特殊变量:$*、$@、$#、$n(n > 0,即$0是脚本名而不是函数名),相当于在函数内默认定义了这几个特殊变量。函数可以访问外部可见变量(全局变量和其它各种环境变量),也可以定义仅内部使用的局部变量(局部变量参考前面介绍的local命令)。
function语法function命令信息:# 通过help命令查看
help function
# 通常语法,以下两种语法功能和作用均一样
# 标准函数语法
function name [()]{ COMMANDS ; }
# 简写函数语法
name () { COMMANDS ; }
注意:函数体内最少有一条命令语句,否则语法报错。函数名与左大括号必需有隔开符(一对小括号、空格、换行均可),函数体中首尾大括号内必需与内部语句使用空格或换行隔开,函数结束大括号必需使用换行或分号与后面的语句分开(函数的申明和函数体都属于函数命令部分,命令的结束需要符合语法)。
示例:
# 定义函数func_show1
function func_show1(){
echo "func_show1-params: $@"
}
# 定义函数func_show2
function func_show2 {
echo "func_show2-params: $@"
}
# 定义函数func_show3
func_show3(){
echo "func_show3-params: $@"
}
# 调用定义的函数
func_show1 test1 && func_show2 test2 && func_show3 test3
# 输出
#func_show1-params: test1
#func_show2-params: test2
#func_show3-params: test3
return命令函数是一个自定义命令,那命令就会有退出值。函数需要通过return命令来自定义退出值,如果不指定return命令则函数会把函数体内最后一个命令的执行退出值返回出来。return命令默认返回值是0(即函数调用成功)
注意:函数的退出值会自动写入到特殊变量$?中。$?是在一个命令或语句执行完后才自动进行赋值修改。
return命令信息:# 通过help命令查看
help return
# 通常语法
return [n]
1、return [n]的n默认是$?,也可以指定为0-255之间的数值。
2、函数体执行结束都没有指定return n命令,则相当于默认执行return $?。
3、return 不指定返回值相当于执行 return $?
4、函数体内执行return命令后函数立即退出函数体
示例:func_test(){
echo "current-\$?:$?"
if [ -n "$1" ];then
if [[ $1 =~ ^[0-9]+$ ]];then
echo 'shell srcipt'|grep -qP 'python' # grep命令匹配失败,即:$?=1
return $1 # 指定函数退出值
else
echo 'shell srcipt'|grep -qP 'python' # grep命令匹配失败,即:$?=1
return # 相当于调用 return $?
fi
fi
echo 'shell srcipt'|grep -qP 'python' # grep命令匹配失败,即:$?=1
}
echo 'shell srcipt'|grep -qP 'python'
# grep命令匹配失败,即:$?=1
## 不传参数则函数不会调用return命令语句,直接返回前一个命令的退出值(也可以说不修改$?,因为$?在当前shell脚本执行环境下共享)
func_test
echo "func-default-\$?:$?"
# 传入一个非数值参数,函数会执行 return 命令语句
# 相当于执行 return $?
func_test a
echo "func-return-\$?:$?"
# 传入一个数值参数,函数内会执行 return $1 命令语句
# 修改$?值为传入的整数值
func_test 0
echo "func-return-\$?:$?"
# 输出:
# current-$?:1
# func-default-$?:1
# current-$?:0
# func-return-$?:1
# current-$?:0
# func-return-$?:0
exit命令exit命令是用来停止当前执行环境继续向下执行(一般用于退出shell脚本继续执行)并设置退出值。exit命令在脚本执行错误或不合理时调用非常实用,exit会在上层执行环境中修改$?值(比如:脚本调用脚本就可以获取子脚本的执行情况)。
注意:exit和return命令功能唯一不同的是return只能用在函数退出,而exit用来退出脚本(也可以放在函数内退出脚本),其它功能和处理规则一样(即修改退出值)。
exit命令信息:# 通过help命令查看
help exit
# 通常语法
exit [n]
示例:
脚本文件 test1.sh#!/bin/bash
if [ -n "$1" ];then
if [[ $1 =~ ^[0-9]+$ ]];then
echo 'shell srcipt'|grep -qP 'python' # grep命令匹配失败,即:$?=1
exit $1 # 指定脚本退出值
else
echo 'shell srcipt'|grep -qP 'python' # grep命令匹配失败,即:$?=1
exit # 相当于调用 exit $?
fi
fi
echo 'shell srcipt'|grep -qP 'python' # grep命令匹配失败,即:$?=1
脚本文件 test2.sh#!/bin/bash
# 不传参数则函数不会调用 exit 命令语句
bash test1.sh
echo "shell-exit-\$?:$?"
# 传入一个非数值参数,函数会执行 exit 命令语句
# 相当于执行 exit $?
bash test1.sh a
echo "shell-exit-\$?:$?"
# 传入一个数值参数,函数内会执行 exit $1 命令语句
# 修改$?值为传入的整数值
bash test1.sh 0
echo "shell-exit-\$?:$?"
调用bash test2.sh
# 输出:
# shell-exit-$?:1
# shell-exit-$?:1
# shell-exit-$?:0
正则表达式shell正则支持正则通用语法。如果熟悉其它语言正则会发现shell正则不支持通用特定转义(比如:\w 、\W 、\d 、\D),仅支持空格换行之类的转义符。
shell正则在不同的命令中会有差异(因为解析引擎不同),比如sed -r和grep -P或[[]]正则就不尽相同。
shell正则主要分:普通字符、子模式、字符类、任意符、重复限定、锚、可选符、转义符。普通字符普通字符是正则原字符匹配语法,即字符是什么样的就匹配什么样的内容(有些正则语法支持大小写修饰可以升级普通字符不区分大小写去匹配)。正则中除了普通字符匹配还有一些高级语法,这些语法是通过一些特殊字符来表示(一般称元字符),如果在普通字符中需要匹配这些特殊字符均需要增加转义符进行处理。
正则表达式主要元字符有:^ $ \ [ ]
( ) . * ? { } + -
子模式 ()子模式是指定括号内的正则为子匹配项,方便增加重复量限定或引用字符替换。同一个正则中可以有多个子模式且允许嵌套,子模式在引用时是通过子模式匹配顺序来的,从左向右且从外向内依次从1开始计数(0是整个正则)。
示例:# 正则表达式 abc(123)
[[ 'abcdabc123abs' =~ abc(123) ]];echo $?
# 判断是否匹配abc123,输出0
echo 'abcdabc123abs'|sed -r 's/abc(123)/\1/g'
# 把abc123中的abc去掉,输出abcd123abs
echo 'abcdabc123abs'|grep -oP 'abc(123)' # 提取abc123,输出abc123
字符类 []字符类是用来代表任选一些或非这些字符集,默认只任匹配一个字符,如果需要多个则需要增加重复量限定。字符类语法是使用对一中括号表示,中括号内字符为可选或排除字符集。任选一些指定符集任选字符类可以指定任何需要的字符组(特殊字符需要转义),字符不分前后均代表可选字符。
示例:# 正则表达式 abc[123]
# 可匹配abs后面是123任意一个数字
[[ 'abcdabc123abs' =~ abc[123] ]];echo $?
# 判断是否匹配,输出0
echo 'abcdabc123abs'|sed -r 's/abc[123]//g'
# 替换掉,输出abcd23abs
echo 'abcdabc123abs'|grep -oP 'abc[123]'
# 提取匹配内容,输出abc1
字符范围 -字符范围方便填写序列字符,主要是字母或数字(比如:[a-z] 和 [A-Z] 或 [0-9])并且可以并列多个(比如:[a-zB-W3-9])。并列代表各并列字符范围都是可选字符(并列不分前后)。
注意:字符范围是从小到大或从前到后,也可以取中某段(比如:[e-n] 或 [5-7] 等),但不逆向指定(比如:[9-5] 或 [h-a] 等)。
字符范围不支持组合(比如:[aa-zz] 或 [100-900] 等),这样写不会报错且只有在-符号左右的第一个字符会进行范围提取,其它字符会按任选指定字符集处理。
示例:# 正则表达式 abc[1-9]
# 可匹配abs后面是1到9间任意一个数字
[[ 'abcdabc123abs' =~ abc[1-3] ]];echo $?
# 判断是否匹配,输出0
echo 'abcdabc123abs'|sed -r 's/abc[1-3]//g'
# 替换掉匹配内容,输出abcd23abs
echo 'abcdabc123abs'|grep -oP 'abc[1-3]'
# 提取匹配内容,输出abc1
特殊字符组特殊字符组是一些特定字符组的便捷表达式,使用特殊字符组可以直接代表对应的字符组。
特殊字符组的语法好比是 [] 嵌套 [:name:],也就是说[:name:]是一个整体并且可以同时并列多个特殊字符组,比如:[[:alpha:][:alnum:]]。
字符组
代替说明
[[:alpha:]]
匹配任意字母字符,不管是大写还是小写
[[:alnum:]]
匹配任意字母数字字符0~9、A~Z或a~z
[[:blank:]]
匹配空格或制表符
[[:digit:]]
匹配0~9之间的数字
[[:lower:]]
匹配小写字母字符a~z
[[:print:]]
匹配任意可打印字符
[[:punct:]]
匹配标点符号
[[:space:]]
匹配任意空白字符:空格、制表符、NL、FF、VT和CR
[[:upper:]]
匹配任意大写字母字符A~Z
示例:# 正则表达式 abc[[:alpha:][:alnum:]]
# 可匹配abs后面是1到9或大小写字母间任意一个
[[ 'abc123abs' =~ abc[[:alpha:][:alnum:]] ]];echo $?
# 判断是否匹配,输出0
echo 'abc123abs'|sed -r 's/abc[[:alpha:][:alnum:]]//g'
# 替换掉匹配内容,输出23abs
echo 'abc123abs'|grep -oP 'abc[[:alpha:][:alnum:]]'
# 提取匹配内容,输出abc1
排除字符集 ^当需要匹配指定字符集时就需要使用到在字符类中括号左边增加^,表示除了这些字符除外。
注意:中括号内^符号必需紧挨着左边中括号,中间不能有其它任何字符否则将不会以排除处理而是包括匹配,上面的几种字符类均可应用到排除字符集。
示例:# 正则表达式 abc[^[:alpha:]4-9]
# 可匹配abs后面不是9到9或大小写字母间任意一个
[[ 'abcdabc123abs' =~ abc[^[:alpha:]4-9] ]];echo $?
# 判断是否匹配,输出0
echo 'abcdabc123abs'|sed -r 's/abc[^[:alpha:]4-9]//g'
# 替换掉匹配内容,输出abcd23abs
echo 'abcdabc123abs'|grep -oP 'abc[^[:alpha:]4-9]'
# 提取匹配内容,输出abc1
任意字符 .很多时候需要匹配一段字符是未知类型(或者是忽略段),任意字符将是一个必备工具。任意字符是一个点,这个点代表任何一个字符(有的正则点只代表非空格字符,要升级点的功能需要增加修饰)。
示例:# 正则表达式 ...
# 匹配任意三个字符一组并全部替换为+
echo 'abc abc 123 abs'|sed -r 's/.../+/g'
# 替换掉匹配内容,输出+++++
重复限定当指定的匹配项会连续重复多次出现就需要使用到重复限定,使用重复限定可以减化匹配语法。重复限定分:0~1次、0次及以上、1次及以上、自定义次数。匹配项是指重复限定符前面的(子模式、字符集、常规一个字符、限定符+前面的匹配项)。
注意:重复限定是贪婪匹配,即只要在重复限定范围内有多少就去匹配多少,而不是按最小重复数去处理。对于重复0次的匹配需要额外注意,尤其是在替换时一定要组合非0次匹配,否则会在每个不匹配串前后产生匹配点并进行替换处理。
重复限定在替换处理中比较直观了解,下面示例就不展示其它命令仅以sed命令为主。
?? 在正则中表示前面的匹配项需要重复0~1次(即有只匹配一次,没有就跳过)。
示例:# 正则表达式: [[:alpha:]][0-9]?
# 将匹配所有前面是一个字母后面是一个数字的串并全部替换为+
echo 'abc123-a0-a1'|sed -r 's/[[:alpha:]][0-9]?/+/g'
# 替换掉匹配内容,输出+++23-+-+
** 在正则中表示前面的匹配项需要重复0次及以上(即有就匹配所有连续重复一次匹配项,没有就跳过)。
示例:# 正则表达式: [[:alpha:]][0-9]*
# 将匹配所有字母并全部替换为+
echo 'abc123-a0-a1'|sed -r 's/[[:alpha:]][0-9]*/+/g'
# 替换掉匹配内容,输出+++-+-+
++ 在正则中表示前面的匹配项需要重复1次及以上(即有最少匹配一次,且后面连续有多少重复均匹配上)。
示例:# 正则表达式: [[:alpha:]]+
# 将匹配所有字母并全部替换为+
echo 'abc123-a0-a1'|sed -r 's/[[:alpha:]]+/+/g'
# 替换掉匹配内容,输出+123-+0-+1
{} 自定义自定义匹配分三种形式:固定次数 {n}、指定次数及以上 {n,}、区间次数 {n, m}。
示例:# 正则表达式: [[:alpha:]]{2}
# 将匹配所有2个字母一起的全部替换为+
echo 'abc123-a0-a1'|sed -r 's/[[:alpha:]]{2}/+/g'
# 替换掉匹配内容,输出+c123-a0-a1
# 正则表达式: [[:alpha:]]{2,}
# 将匹配所有2个及以上字母一起的全部替换为+
echo 'abc123-a0-a1'|sed -r 's/[[:alpha:]]{2,}/+/g'
# 替换掉匹配内容,输出+123-a0-a1
# 正则表达式: [[:alpha:]]{2,5}
# 将匹配所有2至5个字母一起的全部替换为+
echo 'abc123-abcdef0-a1'|sed -r 's/[[:alpha:]]{2,5}/+/g'
# 替换掉匹配内容,输出+123-+f0-a1
限定符允许嵌套使用,比如:(([a-z]+)?-[0-9]+){2,} 。
限定符允许并列连续使用(有的开发语言中的正则不允许重复并列,除非是 .? ),比如: [a-z]? 或 [a-z]?{1,2}。一般不推荐使用并列连续使用重复限定符。
锚 ^$^$是指定正则表达式在待匹配的字符串的开始和结束位置(即必需匹配到指定位置),一般放在正则表达式的首尾处理。^ 是限制正则表达式必需从开始位置进行匹配(一般放在正则表达式最前面),$ 是限制正则表达式必需匹配到结束位置(一般放在正则表达式最后面)。两种位置限定可以同时和单独使用。
示例:# 正则表达式: ^[[:alpha:]]+
# 从开始匹配连续1个及以上字母并替换为+
echo 'abc123-a0-a1'|sed -r 's/^[[:alpha:]]+/+/g'
# 替换掉匹配内容,输出+123-a0-a1
# 正则表达式: [0-9]+$
# 找出结尾连续1个及以上数字并替换为+
echo 'abc123-a01'|sed -r 's/[0-9]+$/+/g'
# 替换掉匹配内容,输出abc123-a+
可选符
如果匹配的内容是确定几种固定规则时没有可选符将很难在一个正则中实现(可以在每个选项规则上增加重复限定为0~1次,但这样会匹配所有的可选规则而不是多选一)。
示例:# 正则表达式: abc|123|a.
# 将abc或123或a后面任意字符替换为+
echo 'abc123-a0-a1'|sed -r 's/abc|123|a./+/g'
# 替换掉匹配内容,输出++-+-+
转义符 \如果需要匹配前面的特殊字符时就必需使用转义,转义后这些特殊字符将没有特殊功能而是一个普通字符串,可以正常进行匹配,转义符可以转义自己。
示例:# 正则表达式: [\\\*\-\$]+
# 把所有\*-$替换为+
echo '.***/[](\\){$}?$^'|sed -r 's/[\*\-\$]+/+/g'
# 替换掉匹配内容,输出.+/[](+){+}?+^
模式匹配模式匹配是一种简易的正则表达式,它舍弃了正则是很多高级功能,保留一些高效语法,在使用模式匹配时最好先了解下正则。
模式匹配保留了shell正则语法:字符类、转义符(各种括号和空格通配符等需要转义才能用于匹配这些字符);增加:通配符*(相当于正则表达式 .* 的简写)。也就是说模式匹配去掉正则:可选符(case支持可选命令)、子模式、锚、任意字符、\s等转义符、重复符、自定义量词等功能,其它语法均可正常使用。
编写时需要注意与正则表达式区别,在模式匹配中不支持的符合均为普通匹配且特殊符号需要转义。模式匹配主要用于[[]]和case命令中,其中可选任只能用于case命令中。
注意:小括号在模式匹配中不支持,如果需要匹配小括号需要增加转义符
示例:# 判断字符串是否符号版本号格式
[[ '4.50v' == [0-9].[0-9][0-9][[:alpha:]] ]];echo $? # 输出0
重定向重定向分输入重定向和输出重定向,它提供一种语法将输入或输出的的信息进行转移,实际应用中重定向很常用。重定向可以理解为待重定向命令的可选子命令,它与重定向命令组成一个完整的命令调用,一般附加在命令的末尾。重定向并是不像串联调用那样连接多个命令,重定向是就是当前命令的一部分,使用时需要多加注意,因为这种特性会产生很多技巧使用(前面在./脚本调用和while循环等地方也简单介绍部分)。
linux系统一切都用文件,包括运行的所有进程和硬件设备,比如:进程放在 /proc 目录下,设备放在 /dev 目录下。
一般情况下,每个Unix/Linux命令运行时都会有以下三个文件:
在重定向的过程中经常会使用到三个文件描述符:0、1、2 ,这三个文件描述符可以直接使用且默认都是打开的。文件描述符
文件名
对应硬件
说明
stdin
键盘
标准输入文件
1
stdout
显示器
标准输出文件
2
stderr
显示器
标准错误输出文件
文件描述符可以理解为文件的别名或链接。stdin、stdout、stderr默认都是打开的,在重定向的过程中,0、1、2 这三个文件描述符可以直接使用。
输入重定向输入重定向使用 < 或 << 符号表示,输入重定向是将标准输入文件0指向指定的文件。输入重定向只能在需要操作文件的命令上使用(比如命令:grep、wc、cat等),如果命令不需要操作文件则输入重定向无效或报错(比如命令:echo、print等)。
注意:输入重定向不能使用上面说的文件描述符。可以理解为:文件描述符1和2是输出文件不能用于读,而文件描述符0是要重定向的文件。但你可以直接使用stdin、stdout、stderr这三个文件,分别在/dev目录下,使用时可指定下目录。
输入重定向 << 是重定向标准输入文件到指定的文件命令符。< 左边是要调用的命令,右边是需要指定重定向到的文件名。
重定向语法:COMMAND < filename
示例:cat </etc/profile
# 输出文件/etc/profile内容
输入重定向 <<<< 是重定向标准输入文件到Heredoc结构字符串(不是文件名)命令符。<< 左边是要调用的命令,右边是Heredoc结构字符串。
注意: << 是Heredoc结构字符串的开始符,所以使用<<重定向就必需使用Heredoc结构字符串语法来编写。
重定向语法:
COMMAND <<TAG_NAME
...
TAG_NAME
注意:TAG是起止标识符,标识符必需首尾相同,中间是任意字符且允许换行。结束标识符必需在当前行首且以换行结束不能再包含其它字符否则不会解析为结束标识符。标识符可以任意命名(部分特殊字符不允许用于标识符命名,一般推荐使用变量命名规则)。
<< 是换行输入的,当在命令行中使用时可以一行一行的输入且不需要使用转义符来处理换行。
示例:cat <<EOF
shell srcipt!
EOF
# 输出:
# shell srcipt!
输出重定向重定向输出在shell脚本中使用颇多,并且可以并列多次重定向输出。重定向输出使用 > 或 >> 符号表示。左边是要调用的命令,右边是重定向的文件。 > 是覆盖到输出文件,>> 是追加到输出文件。
注意:重定向输出可以指定0、1、2这三个文件描述符(需要增加&符号)。2标准错误输出文件是命令异常抛出的信息,不受反引号、$(())等方式提取,当需要屏蔽错误输出时重定向输出是一个非常简单的途径(一般将错误信息重定向到/dev/null中)。
重定向语法:# 重定向输出覆盖到输出文件
COMMAND [1|2]>[&][0|1|2|filename]
# 重定向输出追加到输出文件
COMMAND [1|2]>>[&][0|1|2|filename]
说明:输出重定向不仅可以把命令的各种输出信息重定向到stdin、stdout、stderr,还可以重定向到指定文件。在使用到0、1、2这三个文件描述符时与重定向输出符不能有空格,但指定其它文件时可以有空格。
示例:# 特意输出错误信息
echo 'error' >&2
# 将命令的错误信息屏蔽
echo 'error' 2>/dev/null
# 将命令的所有输出信息屏蔽
echo 'error' 2>&1 >/dev/null
# 置空或创建空文件
> /tmp/log
# 向文件追加内容
echo 'add line' >>/tmp/log
echo 'add line' >>/tmp/log
# 此处记得查看下 /tmp/log 文件内容
# 覆盖文件内容
echo 'one line' >/tmp/log
常用命令下面列出一些常用命令,对于编写shell脚本很有用,实际应用中命令远不止这些,但它们使用的规则基本相同。命令总体分两类,内建命令和外部扩展命令,不同的命令处理方式略有区别。
命令在执行结束后都会有退出值,命令执行成功是0,失败是非0(多数命令是1)。这些退出值均可用于条件判断处理。
shell内建命令因为shell本身是一个工具,它负责解析shell脚本代码并执行,在工具内部也提供了一些特殊常用或必备内置命令,这些命令被认为是高效的。内置命令在shell中是肯定能使用,下面列举一些常用的(前面已经细说过的就不再重复列举)helphelp是内置专用帮助命令,用来查看内置命令的使用信息,如果不清楚一些内置命令信息这条命令可能是你最快了解的途径之一,当然这个命令展示出来的帮助信息有限,但基本上能满足常规使用。
示例:# 展示出所有内置命令列表
help
# 查看help命令信息
help help
pwdpwd是输出当前工作目录。shell命令搜索目录分:环境目录、工作目录、根目录。目录正确才能找到对应的文件。环境目录一般用于命令搜索,工作目录和根目录用于命令搜索和文件使用。工作目录下一般使用的是相对路径,使用方便。根目录是绝对路径开始,绝对路径能保证目录完整无误特别是在多个相同命令或文件时很实用。
示例:# 展示当前工作目录
pwd
cdcd是工作目录切换命令
示例:cd ../
# 将级目录切换为工作目录
cd /use/local
# 指定绝对路径为工作目录
readread是标准输入文件读取单行数据命令。这个命令可以用来读取键盘输入,当使用重定向的时候,可以读取文件中的一行数据。
示例:# 读取单行标准输入数据并写入到变量LINE_STR中
read LINE_STR
# 读取/etc/profile文件第一行数据并写入到变量LINE_STR中
read LINE_STR < /etc/profile
killkill是有PID或JOBSPEC的进程发送停止信号数值(默认是15,即正常停止一个进程),一般在强制停止服务或shell脚本时很有用。
示例:kill -l
# 查看kill支持传入信号数值
kill 222 # 正常停止进程ID是222的进程
kill -9 222 # 强制杀掉进程ID是222的进程
shell外部命令外部命令主要分为:系统携带、另外安装。特别需要注意的是系统对文件的权限控制(读、取、执行),如果是命令必需有可执行权限否则不能直接调用。下面简单列几个外部命令的基本使用。
注意:外部命令在使用前如果对命令功能和参数有些不清楚可以通过命令自带的帮助参数来查看(一般查看帮助信息使用参数 -h 或 --help)。
如果不支持脚本信息参数可以使用info命令查看,比如查看awk命令说明:info awk
sedsed是文件替换命令,详情查看awkawk是一个强大的文本分析工具,详情查看grepgrep是文件内容搜索命令,详情查看findfind是文件搜索命令,详情查看psps进程查看命令,详情查看netstatnetstat是网络查看命令,详情查看wgetwget是网络下载工具,详情查看tartar是解压压缩工作,详情查看tailtail是文件尾部内容提取命令,详情查看headhead是文件头部内容提取命令,详情查看whichwhich是命令搜索,详情查看cpcp是文件或目录复制命令,详情查看mvmv是文件或目录移动命令,详情查看rmrm是文件或目录删除命令,详情查看vi & vimvi 和 vim是文件编辑器,详情查看chmodchmod是文件或目录权限修改器,详情查看chownchown是用户或用户组对文件或目录的权限修改器,详情查看xargsxargs是读取文件内容为参数去调用指定命令,详情查看

我要回帖

更多关于 获取快捷指令 的文章

 

随机推荐