shell笔记

是时候整理一番shell了。先说说shell的特点与适用:
Shell有两种执行命令的方式:
交互式(Interactive):解释执行用户的命令,用户输入一条命令,Shell就解释执行一条。
批处理(Batch):用户事先写一个Shell脚本(Script),其中有很多条命令,让Shell一次把这些命令执行完,而不必一条一条地敲命令。
Shell是一种脚本语言,那么,就必须有解释器来执行这些脚本。Unix/Linux上常见的Shell脚本解释器有bash、sh、csh、ksh等,习惯上把它们称作一种Shell。我们常说有多少种Shell,其实说的是Shell脚本解释器。
bash是Linux标准默认的shell,本教程也基于bash讲解。bash由Brian Fox和Chet Ramey共同完成,是BourneAgain Shell的缩写,内部命令一共有40个。Linux使用它作为默认的shell是因为它有诸如以下的特色:

  • 可以使用类似DOS下面的doskey的功能,用方向键查阅和快速输入并修改命令。
  • 自动通过查找匹配的方式给出以某字符串开头的命令。
  • 包含了自身的帮助功能,你只要在提示符下面键入help就可以得到相关的帮助。

因为Shell似乎是各UNIX系统之间通用的功能,并且经过了POSIX的标准化。因此,Shell脚本只要“用心写”一次,即可应用到很多系统上。因此,之所以要使用Shell脚本是基于:

  • 简单性:Shell是一个高级语言;通过它,你可以简洁地表达复杂的操作。
  • 可移植性:使用POSIX所定义的功能,可以做到脚本无须修改就可在不同的系统上执行。 开发容易:
  • 在短时间内完成一个功能强大又妤用的脚本。

但是,考虑到Shell脚本的命令限制和效率问题,下列情况一般不使用Shell:

  • 资源密集型的任务,尤其在需要考虑效率时(比如,排序,hash等等)。
  • 需要处理大任务的数学操作,尤其是浮点运算,精确运算,或者复杂的算术运算(这种情况一般使用C++或FORTRAN 来处理)。
  • 有跨平台(操作系统)移植需求(一般使用C 或Java)。 复杂的应用,在必须使用结构化编程的时候(需要变量的类型检查,函数原型,等等)。
  • 对于影响系统全局性的关键任务应用。 对于安全有很高要求的任务,比如你需要一个健壮的系统来防止入侵、破解、恶意破坏等等。
  • 项目由连串的依赖的各个部分组成。 需要大规模的文件操作。 需要多维数组的支持。 需要数据结构的支持,比如链表或数等数据结构。
  • 需要产生或操作图形化界面 GUI。 需要直接操作系统硬件。 需要 I/O 或socket 接口。 需要使用库或者遗留下来的老代码的接口。
  • 私人的、闭源的应用(shell 脚本把代码就放在文本文件中,全世界都能看到)。

再说说shell的语法:我感觉就是语法弱化版的c,但是可以很方便地执行各种命令,这是c不能简单做到的

#!/bin/bash
echo "Hello World !"

“#!” 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种Shell。echo命令用于向窗口输出文本。

chmod +x ./test.sh  #使脚本具有执行权限
./test.sh  #执行脚本

读入:

echo "What is your name?"
read PERSON
echo "Hello, $PERSON"

注释:顶格写#之后的就是注释,只有单行注释
如果在开发过程中,遇到大段的代码需要临时注释起来,过一会儿又取消注释,怎么办呢?每一行加个#符号太费力了,可以把这一段要注释的代码用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果
变量:

定义变量时,变量名不加美元符号 使 即可,已定义的变量,可以被重新定义,使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。使用 unset 命令可以删除变量。
shell运行时存在3种变量类型:
运行shell时,会同时存在三种变量:
1) 局部变量
局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
2) 环境变量
所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
3) shell变量
shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行

变量名只能包含数字、字母和下划线,因为某些包含其他字符的变量有特殊含义,这样的变量被称为特殊变量。

$0 当前脚本的文件名
$n	传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2$# 传递给脚本或函数的参数个数。
$* 传递给脚本或函数的所有参数。
$@ 传递给脚本或函数的所有参数。
$* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"$1" "$2""$n" 的形式输出所有参数。但是当它们被双引号(" ")包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2$n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2""$n" 的形式输出所有参数。
$? 上个命令的退出状态,或函数的返回值。
$$    当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。


转义字符:

\\  反斜杠
\a  警报,响铃
\b  退格(删除键)
\f  换页(FF),将当前位置移到下页开头
\n  换行
\r  回车
\t  水平制表符(tab键) 
\v  垂直制表符

echo 命令的 -E 选项禁止转义,默认也是不转义的;使用 -n 选项可以禁止插入换行符。

Shell可以先执行命令,将输出结果暂时保存,在适当的地方输出:

`command`

注意是反引号,不是单引号,这个键位于 Esc 键下方。

变量替换:

${var} 变量本来的值
${var:-word}   如果变量 var 为空或已被删除(unset),那么返回 word,但不改变 var 的值。
${var:=word}   如果变量 var 为空或已被删除(unset),那么返回 word,并将 var 的值设置为 word。
${var:?message}    如果变量 var 为空或已被删除(unset),那么将消息 message 送到标准错误输出,可以用来检测变量 var 是否可以被正常赋值。若此替换出现在Shell脚本中,那么脚本将停止运行。
${var:+word}   如果变量 var 被定义,那么返回 word,但不改变 var 的值。

Bash 支持很多运算符,包括算数运算符、关系运算符、布尔运算符、字符串运算符和文件测试运算符。
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。
expr 是一款表达式计算工具,使用它能完成表达式的求值操作。expr相关见本文末。

关系运算符:

-eq 检测两个数是否相等,相等返回 true。    [ $a -eq $b ] 返回 true-ne 检测两个数是否相等,不相等返回 true。   [ $a -ne $b ] 返回 true-gt 检测左边的数是否大于右边的,如果是,则返回 true。 [ $a -gt $b ] 返回 false-lt 检测左边的数是否小于右边的,如果是,则返回 true。 [ $a -lt $b ] 返回 true。
-ge 检测左边的数是否大等于右边的,如果是,则返回 true。    [ $a -ge $b ] 返回 false。
-le 检测左边的数是否小于等于右边的,如果是,则返回 true。   [ $a -le $b ] 返回 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

字符串运算符:

**= 检测两个字符串是否相等,相等返回 true**。    [ $a = $b ] 返回 false。
!=  检测两个字符串是否相等,不相等返回 true。 [ $a != $b ] 返回 true。
-z  检测字符串长度是否为0,为0返回 true。  [ -z $a ] 返回 false。
-n  检测字符串长度是否为0,不为0返回 true。 [ -z $a ] 返回 true。
str 检测字符串是否为空,不为空返回 true。   [ $a ] 返回 true

注意这里的相等并不是我们认为的 == 而是=就行了

文件测试运算符:

-b file 检测文件是否是块设备文件,如果是,则返回 true。  [ -b $file ] 返回 false-c file 检测文件是否是字符设备文件,如果是,则返回 true。 [ -b $file ] 返回 false-d file 检测文件是否是目录,如果是,则返回 true。 [ -d $file ] 返回 false-f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。    [ -f $file ] 返回 true-g file 检测文件是否设置了 SGID 位,如果是,则返回 true。  [ -g $file ] 返回 false-k file 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。  [ -k $file ] 返回 false-p file 检测文件是否是具名管道,如果是,则返回 true。   [ -p $file ] 返回 false-u file 检测文件是否设置了 SUID 位,如果是,则返回 true。  [ -u $file ] 返回 false-r file 检测文件是否可读,如果是,则返回 true。  [ -r $file ] 返回 true-w file 检测文件是否可写,如果是,则返回 true。  [ -w $file ] 返回 true-x file 检测文件是否可执行,如果是,则返回 true。 [ -x $file ] 返回 true-s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 [ -s $file ] 返回 true-e file 检测文件(包括目录)是否存在,如果是,则返回 true。    [ -e $file ] 返回 true

单引号:
单引号字符串的限制:
单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
单引号字串中不能出现单引号(对单引号使用转义符后也不行)。
双引号:
双引号的优点:
双引号里可以有变量
双引号里可以出现转义字符

字符串操作:

#拼接字符串
your_name="qinjx"
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting $greeting_1

#获取字符串长度
string="abcd"
echo ${#string} #输出 4

#提取子字符串
string="alibaba is a great company"
echo ${string:1:4} #输出liba

数组:

array_name=(value0 value1 value2 value3)

使用@ 或 * 可以获取数组中的所有元素:

${array_name[*]}
${array_name[@]}

# 取得数组元素的个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得数组单个元素的长度
lengthn=${#array_name[n]}

printf:
printf 命令用于格式化输出, 是echo命令的增强版。它是C语言printf()库函数的一个有限的变形,并且在语法上有些不同。printf 由 POSIX 标准所定义,移植性要比 echo 好。
printf 不像 echo 那样会自动换行,必须显式添加换行符(\n)

结构化语句:

if  xxx
then xxx
elif    xxx
then    xxx
elif    xxx
then    xxx
else    xxx
fi
casein
模式1)
    command1
    command2
    command3
    ;;
模式2)
    command1
    command2
    command3
    ;;
*)
    command1
    command2
    command3
    ;;
esac

例如写一个执行命令判断选项的:

#!/bin/bash

option="${1}"
case ${option} in
   -f) FILE="${2}"
      echo "File name is $FILE"
      ;;
   -d) DIR="${2}"
      echo "Dir name is $DIR"
      ;;
   *) 
      echo "`basename ${0}`:usage: [-f file] | [-d directory]"
      exit 1 # Command to come out of the program with status 1
      ;;
esac

for循环:

#!/bin/bash

for FILE in $HOME/.bash*
do
   echo $FILE
done

while:

echo 'type <CTRL-D> to terminate'
echo -n 'enter your most liked film: '
while read FILM
do
    echo "Yeah! great film the $FILM"
done

until:

#!/bin/bash

a=0

until [ ! $a -lt 10 ]
do
   echo $a
   a=`expr $a + 1`
done

break跳出循环:

#!/bin/bash
while :
do
    echo -n "Input a number between 1 to 5: "
    read aNum
    case $aNum in
        1|2|3|4|5) echo "Your number is $aNum!"
        ;;
        *) echo "You do not select a number between 1 to 5, game is over!"
            break
        ;;
    esac
done

在嵌套循环中,break 命令后面还可以跟一个整数,表示跳出第几层循环。

continue同c语言一样,仅仅跳出本次,continue 后面也可以跟一个数字,表示跳出第几层循环。

函数:
定义:

function function_name () {
    list of commands
    [ return value ]
}

注意点归纳如下:
1、Shell 函数必须先定义后使用
2、函数名前加上关键字 function 是可选的
3、函数返回值,可以显式增加return语句;如果不加,会将最后一条命令运行结果作为返回值。
4、Shell 函数返回值只能是整数,一般用来表示函数执行成功与否,0表示成功,其他值表示失败。如果 return 其他数据,比如一个字符串,往往会得到错误提示:“numeric argument required”。
如果一定要让函数返回字符串,那么可以先定义一个变量,用来接收函数的计算结果,脚本在需要的时候访问这个变量来获得函数返回值
5、调用函数只需要给出函数名,不需要加括号。
6、像删除变量一样,删除函数也可以使用 unset 命令,不过要加上 .f 选项:

unset.f fun_name

7、在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 n 1表示第一个参数, 2...10 {10}的形式
8、函数内部特殊的参数

$# 传递给函数的参数个数。
$* 显示所有传递给函数的参数。
$@$*相同,但是略有区别,请查看Shell特殊变量。
$? 函数的返回值。

输入输出重定向:

#输入重定向
command > file  
#输出重定向
command < file  

command > file  将输出重定向到 file
command < file  将输入重定向到 file
command >> file 将输出以追加的方式重定向到 file
n > file    将文件描述符为 n 的文件重定向到 file。
n >> file   将文件描述符为 n 的文件以追加的方式重定向到 file。
n >& m  将输出文件 m 和 n 合并。
n <& m  将输入文件 m 和 n 合并。
<< tag  将开始标记 tag 和结束标记 tag 之间的内容作为输入。

重定向方式——嵌入文档:

command << delimiter
    document
delimiter

它的作用是将两个 delimiter 之间的内容(document) 作为输入传递给 command。结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。开始的delimiter前后的空格会被忽略掉。

包含外部脚本:
2种方法:

. filename
#注意点 跟 filename之间有个空格

或者:

source filename

》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》

下面简单介绍expr命令:
用途
求表达式变量的值。
语法
expr Expression
描述
expr 命令读入 Expression 参数,计算它的值,然后将结果写入到标准输出。
您必须对 Expression 参数应用以下规则:

  • 用空格隔开每个项。
  • 用 / (反斜杠) 放在 shell 特定的字符前面。
  • 对包含空格和其他特殊字符的字符串要用引号括起来。

用法:
1,关系或数学运算,

  • Expression1 /| Expression2 返回 Expression1 如果它不是空值或者 0 值的话,否则返回 Expression2 。
  • Expression1 /& Expression2 返回 Expression1 如果两个表达式都不是空值或者 0 值,否则返回一个 0 值。
  • Expression1 { =, />, />=, /<, /<=, != } Expression2 如果两个表达式都是整数,返回整数比较的结果;否则它返回的是字符串比较的结果。
  • Expression1 {+, - } Expression2 整数值变量的加或者减。
  • Expression1 { /*, /, % } Expression2 整数值变量的乘、除或者提供除法的余数。

2、匹配字符串

Expression1 : Expression2
将 Expression1 的运算得到的字符串与 Expression2 的运算结果的正则表达式模式进行比较。正则表达式语法与 ed 命令相同,除了所有的模式固定到字符串的开始之外(也就是说,只有以字符串的第一个字符开始的序列才被正则表达式匹配)。因此 ^ (插入符号) 在这种情况下就不是特殊字符。
一般地,匹配运算符返回匹配的字符个数(失败的时候返回 0)。
如果模式包含了一个子表达式,也就是:
/( Expression /),则会返回包含了实际匹配的字符的字符串。

expr match String1 String2 #与 Expression1 : Expression2 相同。
expr length String1 #返回 String1 的长度。
expr index String1 String2 #返回 String1 中包含 String2 中任意字符的第一个位置。
expr substr String1 StartPosition Length
返回一个以 StartPosition 的字符开始的在 String1 中的字符串,并且是 Length 长度的字符串。

例如:

要想返回 $SHELL 环境变量 /usr/bin/ksh 的长度,请输入:
expr length $SHELL
显示以下内容:
 12

要想返回 "de" 字符串中的任何一个字符在 "abcdef" 中出现的第一个位置,请输入:
expr index abcdef de
显示以下内容:
 4

/usr/bin/expr 包含了 expr 命令。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值