shell笔记

来源:互联网 发布:杭州java培训机构排名 编辑:程序博客网 时间:2024/06/03 10:06

是时候整理一番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/bashecho "Hello World !"

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

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

读入:

echo "What is your name?"read PERSONecho "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  xxxthen xxxelif    xxxthen    xxxelif    xxxthen    xxxelse    xxxfi
casein模式1)    command1    command2    command3    ;;模式2)    command1    command2    command3    ;;*)    command1    command2    command3    ;;esac

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

#!/bin/bashoption="${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/bashfor FILE in $HOME/.bash*do   echo $FILEdone

while:

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

until:

#!/bin/basha=0until [ ! $a -lt 10 ]do   echo $a   a=`expr $a + 1`done

break跳出循环:

#!/bin/bashwhile :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        ;;    esacdone

在嵌套循环中,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中,调用函数时可以向其传递参数。在函数体内部,通过 n1表示第一个参数,2...10{10}的形式
8、函数内部特殊的参数

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

输入输出重定向:

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

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

command << delimiter    documentdelimiter

它的作用是将两个 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 命令。

0 0