shell学习笔记(二):《Unix Shell编程》学习笔记

1、shell中的变量赋值时等号两边都不能留空格,这点与平常C语言习惯不一样。


2、shell没有数据类型的概念,使用前也无需申明,不管什么值,shell都简单理解成字符串,但可以通过特定 的内部操作,对变量做整数运算。


3、echo ${#str}显示str的字符个数。


4、shell先做变量名替换,再做文件名替换。


5、要在变量名后面跟字母、数字或下划线的时候,需要使用大括号,如${filename}x。


6、shell内整数算术运算扩展的格式是$((expression)),expression是表达式,注意表达式中引用变量的值时无需在前面加$符号,例如:str=12345;echo $((str*2));如果表达式中的变量未定义或空串,就当做0,在表达式内的运算符之间可以留空格,如i=$((i * 5)),甚至还可以使用逻辑运算,如ret=$(( i >= 0 && i <= 100 )),总体来讲,shell对算术运算这套扩展基本上是基于C语言的,但不支持浮点运算,支持整除,求余运算。


7、shell的浮点运算需要借助bc、awk命令来实现。


8、shell中的$()与``等效,返回其中的命令的执行结果。


9、单双引号的区别:二者作用类似,但是双引号没有那么严格,单引号告诉shell忽略所包含的所有特殊字符,而双引号只要求忽略大多数,在双引号中$、`、\(美元符号、反引号、反斜杠)三种字符不被忽略,其余都当做字符串处理。


10、特殊变量:$1,$2,$3…,shell自动把第一、二、三个参数存在特殊变量1,2,3中。$#存的是命令行中所键入的参数个数,$*则代表全部参数。另外当程序参数个数超过十个后,第10个以上的参数引用时必须${10}这样的格式,否则shell会解析成$1后面加一个0的${1}0。而程序名称存储在$0中,类似于C的main。


11、shift命令:shift命令的作用是将参数位置全部左移一次,即原来的$2变成$1,原来的$3变成$2,原来的$1消失,同时$#减一。shift后面跟数字时可以一次移动几个位置,当没有变量可移动时某些shell可能报错。


12、退出状态:0表示成功,非0表示失败;管道线的退出状态为最后一个命令的退出状态;$?表示最后一次命令执行的退出状态。


13、test命令:test用于测试表达式的真假,为真其返回的退出状态为0,否则为非0;test等同于[ ],且后者更为公认、可读,在[之后和]之前必须留空格。


14、空命令:空命令就是一个冒号:,它什么也不做,只是为了满足某些场合的格式需要。


15、理解$@与$*的区别:
   假如有程序args如下:
       for x in $*(或for x in "$@")
       do
           echo $x
       done

   执行args a b c二者没区别,执行args 'a b' c时二者就有区别了,后者能把'a b'作为一个参数显示,而前者不能,当$@不加引号时二者相同(for x in "$@" 可以简写成for x)。


16、跳出循环用break命令;true命令、false命令什么也不做只是返回为0和不为0的退出状态,前者跟空命令:一样;当break n时,程序立即退出最里层的n层循环;同样还有continue,语义与C语言的关键词一样,continue也可接n。


17、循环也可以输入输出重定向及管道输入输出。


18、单行书写for循环语句的语法是:for ;do ;done.


19、getopts命令是专门设计用于处理程序参数的问题的,很适合做命令,《Unix Shell编程》书中第9.5节(P176)做了比较详细的介绍。


20、basename命令:取出路径名的最后一个文件(夹)名,如basename /home/wuchuan/a.c 打印a.c。


21、特殊变量$$,存储着当前shell进程的PID。


22、&&与||:当前一个命令执行成功时才执行&&后的命令,当||前的命令执行不成功时就执行后面的命令直到有一条命令成功就停止执行。


23、printf与echo不同,它不会自动在输出后添加换行符,但它可以理解echo中相同的转义字符。


24、按行循环取文件中的内容的两种方法:
    cat ./data |
    while read line#若格式固定(如每行2个整数,中间空格)也可以用while read n1 n2来取出每个数
    do
        ...
    done
    而while read line < ./data则不能达到循环每行取的效果,只能取到第一行,必须重定向给整个循环:
    while read line; do echo "$line"; done < ./data

    这就是循环内语句重定向和整个循环重定向的区别。


25、局部变量和导出变量的小结:
    ①没有导出的变量是局部变量,子shell不知道它的存在;
    ②导出变量被复制到子shell的环境中,在其中可以存取和修改它们,但是改动的仅仅是副本,对父shell中的变量没有影响;
    ③可以在给变量赋值之前或之后的任何时候导出该变量;

    导出变量的这些特性对子shell有效,对孙子shell也一样。export或export -p命令可以看到所有的导出变量,包括从父shell继承而来的变量。


26、shell用来作命令提示符的显示字符存在变量PS1中,可把它改成任何字符(串);辅助命令提示符一般是>,它存在PS2中,也可以随意修改它;宿主目录存在HOME变量中。


27、shell中有个特殊的内部命令.(读作"dot"),它的一般格式是. file,作用是在当前shell中运行file的内容,也就是由原来的shell来执行file中的命令,不产生子shell来执行,常用来配置不同的环境变量。/etc/profile中就有使用该命令(该命令个人以为还可以理解为c的#include 语句)。


28、(...)和{...; }结构:都是命令(组)的执行方式,前者在子shell中执行,后者在当前shell执行。如果大括号中的命令要打在同一行,左括号后必须有一个空格,如{ cd ..;ls;}.


29、除了设置变量值并将其export之外,还有另外一种方法可以向子shell传递变量:
    DBHOME=/usr/db DBID=452 ./dbrun #在命令名前赋值变量即可传递,当前shell并不知道这些变量
    其实际上等同于:

    (DBHOME=/usr/db;DBID=452;export DBHOME DBID;./dbrun)


30、unset命令:unset用于删除变量,既可以删除导出变量,又可以删除局部变量。但不能删除只读变量,也不能删除IFS,MAILCHECK,PATH,PS1,PS2等变量,有些老版本shell不支持unset。unset -f 删除函数定义。


31、[[ ]]与[ ]有何区别?请看另一篇笔记shell比较与条件判断


32、shell中经常将一些垃圾信息丢弃到/dev/null中去,尤其是在测试命令是否存在时。常用type命令测试命令是否存在,type亦可得知命令类型。


33、终端类型存储在变量$TERM中。


34、${param:-value}:该结构的意思是如果param为空表达式的值就为value,否则就为param的值,但是param本身的值并不变化。比如/etc/profile中有:

         export EDITOR=${EDITOR:-/usr/bin/vim},等同于:

         [ -z "$EDITOR" ] && EDITOR=/usr/bin/vim
      而另一个相似的结构是${param:=value},区别在于,当param为空时,不但使用value,还把它赋值给param,此时param不能是数字(前者中param可以是数字),另外这个结构不能作为单独命令出现,因为shell在完成替换后就会试图执行替换的结果,这样一般都会报错,要把这种结构作为独立命令使用,常借助于空命令 ,放在它前面,并且中间有空格,比如: ${BOOK:=$HOME/phonebook}。

      还有{param:?value}以及{param:+value}。{param:?value}意思是如果param不为空就使用param的值,否则打印value到标准错误中,然后退出(如果是登录shell,并不会导致注销),如果省略了value,则按系统提示 信息输出,常用于检查变量是否设置且不为空,如: ${TEXT:?} ${BOOK:?} ${WORK:?}。

      而{param:+value}的意思是如果param不为空则这种结构的值替换为value,否则什么也不做。


35、模式匹配结构:posix标准shell定义了四种模式匹配结构,${var%pattern},${var%%pattern},${var#pattern},${var##pattern}.%从右往左删除最小的匹配内容,%%从右往左删除最长的匹配内容,#从左往右删除最小的匹配内容,##从左往右删除最长的匹配内容,他们都不会改变var的值,删除后的值就是整个结构的值,没任何匹配时就是var的值,这里的模式的正则表达式跟文件名正则表达式一样。匹配有很多用处,如:
    [ ${file%.o} == $file ] && echo "file is .o file"
    echo ${PATH##*/} #类似于basename命令

    echo ${#str} #统计str字串的字符个数


36、set -x;set +x 这两个命令配对使用(不是必须,可以没有set +x,这样set -x作用到文件结束),会让其间的程序进入跟踪模式,功能与sh -x 选项一样,但不会跟踪子shell。


37、没有参数的set命令会按字母顺序列出环境中的所有变量,不管是局部变量还是导出变量。  


38、没有办法给位置参数直接赋值,只能通过shift和set命令来改变他们。使用set后,以前存在于$1\$2\$3..中的值就永远失去了,新的值将取代它们,$#、$*等值也重设了。         书上举了这样一个巧妙的例子:

    read line
    set $line
    echo $#
可以用这段程序来统计一行中键入的单词个数(采用shell对词的定义)。所以set经常用于解析从文件和终端读入的数据。但是这个例子还有缺陷,当行输入以-号开头时set就会认为是它带的参数,这时候多半就会报错,另外如果是空行,就成了光set命令,会打印全部变量了。要防止这两种错误,需要使用set的--参数,所以修改后的代码是:
    set -- $line

    set是shell内部命令,执行速度较其他命令更快。


39、IFS变量:特殊的shell变量,代表内部字段分隔符(internal field seperator),在解析read命令读入的数据和命令替换的结果,以及进行变量替换时,shell要用到这个变量的值。 可以将其改成任意字符或任一组字符以便解析。改变IFS经常与set变量一起使用,非常有效率(都是内部命令)。因为IFS将影响所有解析,所有在改变它之前应先保存原来的值,并且在使用后恢复原值。


40、readonly:readonly命令用来使得变量将是只读的,如果之后试图修改变量的值,shell会报错。变量的只读属性并不会传递给子shell,而且一旦在一个shell中使变量只读以后,就没办法再撤销。


41、eval命令:当eval后接一条普通命令时,shell在执行该命令之前会扫描它两次。对于一般的命令它没什么特别之处,但是对于在命令中含有变量的情况下经常使用,可以避免一些错误,具体而言,如果变量中包含任何需要shell直接在命令行中看到的字符(即,不是直接替换的结果),就可以使用eval。命令结束符(;、|、&),I\O重定向符(<、>)和引号就属于对shell具有特殊意义的符号,必须直接出现在命令行中。书上举了几个eval的详细例子。


42、wait命令:等待子shell执行完毕再执行当前shell接下来的语句(父子shell默认是异步的)。当她接进程标识符时就专门等待该子进程,否则等待所有子进程执行完成。shell把最后一个送到后台的进程标识存在$!变量中。


43、trap命令用于信号处理。命令格式:

              trap commands signals
    如果要给trap指定多个命令,需要用引号把它们括起来,而指定多个信号则不用。另外需要注意trap中的命令会扫描两遍。
    trap不带参数时显示所有注册了的信号处理。如果给trap指定的命令为空,则忽略该信号。如shell默认:
        trap -- '' SIGTSTP
        trap -- '' SIGTTIN
        trap -- '' SIGTTOU
    如果忽略了一个信号,那么所有子shell也忽略该信号。但是如果设置了收到某信号的动作,则所有的子shell对该信号的处理方式不受影响,依然采用其默认的方式。

    用省略第一个参数的trap命令可以将之前对signals的处理方式撤销,恢复默认。


44、重定向:
     <(输入)、>(输出)、>>(输出追加);
     command 2> file(将命令的标准错误重定向到文件中);
     command >& 2(将命令的标准输出重定向到标准错误);
     <& digit 把标准输入重定向到跟文件描述符digit相关联的文件;
     {command >foo 2>>foo} == {command >foo 2>&1} != {command 2>&1 > foo}(shell从左到右处理重定向)
  另外,还可以使用exec命令在程序中动态的重定向。
     >&-关闭标准输出,<&-关闭标准输入。

     command <<word(内联输入重定向):shell将把其后的各行作为command的标准输入,直到遇到仅包含word的行。这个特性很强大,有多用法。


45、内联输入重定向的最大用处之一是创建shell档案文件。书中举了个例子,但是感觉有点复杂,不知道实用性如何。


46、函数:格式 name() { command; ... command; }
   调用函数时,函数之后的参数依次赋值给函数内部的位置参数$1,$2..;
   函数只在当前shell有效,不能传递到子shell中;
   函数执行速度比等价的shell程序更快,因为shell无需从磁盘搜索程序、打开文件、将内容读入内存;
   unset -f fun,去掉函数fun的定义;

   函数中的exit和return跟C语言的区别一样;


47、history n,查看最近的n条记录;


48、sudo !!,将上一条命令加sudo执行。bash中!!表示在执行一次前一条命令。!string表示再次执行历史记录中以string开头的匹配到的最近的一条命令。bash是linux的标准shell。


49、bash中支持定义局部变量,这样使得递归函数成为可能。局部变量由typeset命令来定义。typeset不是posix标准shell的一部分。bash还支持整形数据类型,用typeset -i var将var定义成整形,整形变量参与算术运算时会比字符串更快一点。整形变量只能赋值整形或整形表达式。


50、alias命令:用于为命令定义一个别名。格式:alias name=string,如alias ll='ls -l'.定义别名时常使用单引号而不是用双引号,这样可将参数替换推迟到别名执行时再进行,否则可能有错。不带参数的alias会列出所有的别名设置。unalias name 删除别名,unalias -a 删除所有别名。


51、bash支持一定的数组功能(数组不是posix shell标准的一部分)。数组起始下标为0,通过下标来访问元素, 不需申明数组的最大元素个数,要使用时直接赋值即可。使用时直接${arr[n]}即可,如果不指明下标,则表示元素0。[*]用来替换数组的所有元素,每个元素之间以一个空格分隔。如echo ${arr[*]}。${#arr[*]}用来表示数组中的实际元素个数。还可以用typeset定义整形数组。


52、作业控制:

shell为作业控制提供了许多便利,任何命令序列就是一道作业。当用后台执行一条命令时,shell在[]内输出作业号,后面再跟进程号。作业完成时,shell也会显示提示信息。jobs命令用于打印未完成的z作业的状态。内置命令kill能终止一道后台作业。其参数可以是进程号或%后跟作业号等形式。按Ctrl+z键可以挂起一台正在前台运行的作业,作业停止时,shell会显示提示信息。停止的作业成为当前作业,不带参数的fg命令可以使当前作业在前台继续执行,bg命令使当前作业在后台重新执行。


53、受限制的shell,限制某些用户的某些行为,从而提高系统安全性,但安全性依然不是很高。


54、cd - 回到上一次访问的目录; cd或cd ~ 回到用户home目录; cd ~linhu 到linhu的主目录;~可以表示$HOME


55、shell执行命令前的搜索顺序:
    1、先检查是不是保留字(比如for和do);
    2、如果不是保留字,并且不在引号中,shell接着检查别名表,如果找到匹配则进行替换;如果别名定义以空格结尾,则对下一个词作别名替换。接着把替换的结果再跟保留字表比较,如果不是保留字则转入第3步;
    3、然后,shell在函数表中查找该命令,如果找到则执行;
    4、接着,shell再检查是不是内部命令(比如cd\pwd);
    5、最后,shell在PATH指定的目录中依次搜索;

    6、如果最终都未能找到命令,则产生"command not found"的错误信息。


56、shell的四种引用机制:
    单引号'': 去掉引号中的所有字符的特殊意义。
    双引号"": 去掉引号中除$,`,\外所有字符的特殊意义。
    \c: 去掉反斜杠之后的字符c的特殊意义。用在双引号中时,如果反斜杠后是$,`,",换行或\,则去除这些特殊字符的特殊意义,否则不做解释;用在行尾时作续行符号(去掉换行符)。

    反引号``: 略


57、times命令:让shell及其子进程使用的总时间写到标准输出,每次显示两个时间,第一个是累计用户时间,第二个是累计系统时间。


58、info命令里有很多命令和gnu libc的宏、函数等的简要说明,是交互式的,按h查看帮助页面。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值