ITPub博客

首页 > Linux操作系统 > Linux操作系统 > shell知识点小结2

shell知识点小结2

原创 Linux操作系统 作者:myownstars 时间:2013-07-02 00:09:26 0 删除 编辑

$? 前一命令退出状态,0表示成功

$$ shell进程ID

PPID 父进程ID

LANG 当前Locale的默认名称,其他LC_*变量会覆盖此值

LC_ALL 当前Locale名称,会覆盖LANG和其他LC_*

PS1(prompt sign) 当前提示字符串

exit 终止整个脚本的执行

return 退出当前函数并返回数字 return N或者$?


shift

shift 3表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1$2$3丢弃,$0不移动。不带参数的shift命令相当于shift 1



getopts

http://blog.sina.com.cn/s/blog_674b5aae0100o2nz.html 

getopts一般格式为:getopts option_string variable

指定变量取值,即在option_string中将一个冒号放在选项后;但当冒号放在第一个选项时,代表其作为一个选项存在;

具体含意为如果某选项设置为取值传递但却未传值时,返回该选项后的信息,若未添加此选项则默认系统也会返回一个错误信息,只是错误信息提示并不明确。

getopts ahfvc: option表明选项ahfv可以不加实际值进行传递,而选项c必须取值。使用选项取值时,必须使用变量OPTARG保存该值。

在使用getopts命令的时候,shell会自动产生两个变量OPTINDOPTARG

OPTIND初始值为1,其含义是下一个待处理的参数的索引。只要存在,getopts命令返回true,所以一般getopts命令使用while循环;

OPTARG是当getopts获取到其期望的参数后存入的位置。

#!/bin/bash

if [ $# -lt 1 ]

then

    echo "there is no option";

else

    while getopts ":Iti:s:v" opt;

    do

        case $opt  in

        I)echo "option is I "

        ;;

        t)echo "option is t "

        ;;

        i)ii=$OPTARG;echo "option is i,the value is $ii";

        ;;

        s)ss=$OPTARG;echo "option is s ,the value is $ss";

        ;;

        v)echo "option is v \n";

        ;;

        :)

                echo ">>> Error: '-$OPTARG' requires an argument"

                ;;

        ?)paralist=-1;

        echo ">>> Error: '-$OPTARG' not supported,please input valid argument [Itisv]"

        ;;

        esac

        done   

fi

下面给出几个执行的例子:

1sh datediff.sh -i 1 -I -v

option is i,the value is 1

option is I

option is v \n

2sh datediff.sh -s -i 1

option is s, the value is -i //s选项后的值

3sh datediff.sh -s       //选项中有前置冒号

>>> Error: '-s' requires an argument

sh datediff.sh -s            //去除选项中的前置冒号后的输出

datediff.sh: option requires an argument -- s

>>> Error: '-' not supported,please input valid argument [Itisv]



subshell和代码块

前者由()包围,后者则是{}

subshell可以在行上任何位置执行,会创建一个新进程,除此之外,调用&提交后台作业/管道,都会创建新进程;

代码块只能位于换行字符、分号或关键字之后,与主脚本共享状态;

http://stackoverflow.com/questions/5547787/running-shell-script-in-parallel
subshell模拟并行运算

#!/bin/bash
for i in $(seq 1 1000)
do
   ( Generating random numbers here , sorting  and outputting to file$i.txt ) &
   if (( $i % 10 == 0 )); then wait; fi # Limit to 10 concurrent subshells.
done
wait


tee

http://linux.chinaunix.net/docs/2007-08-07/4538.shtml 

tee命令会从标准输入读取数据,将其内容输出到标准输出设备,同时又可将内容保存成文件。例如有如下的脚本片段,其作用是获取本机的ip地址:

ipaddr=`/sbin/ifconfig | grep 'inet addr:' | grep -v '127.0.0.1' | cut -d : -f3 | awk '{print $1}'` 

#注意=号后面的整句是用反引号(数字1键的左边那个键)括起来的。

echo $ipaddr

运行这个脚本,实际输出的却不是本机的ip地址,而是广播地址,这时我们可以借助tee命令,输出某些中间结果,将上述脚本片段修改为:

ipaddr=`/sbin/ifconfig | grep 'inet addr:' | grep -v '127.0.0.1' | tee temp.txt | cut -d : -f3 | awk '{print $1}'`

echo $ipaddr

之后,将这段脚本再执行一遍,然后查看temp.txt文件的内容:

$ cat temp.txt

inet addr:192.168.0.1  Bcast:192.168.0.255  Mask:255.255.255.0

我们可以发现中间结果的第二列(列之间以:号分隔)才包含了IP地址,而在上面的脚本中使用cut命令截取了第三列,

故我们只需将脚本中的cut -d : -f3改为cut -d : -f2即可得到正确的结果



trap

http://linux.chinaunix.net/docs/2007-08-07/4538.shtml  

trap命令用于捕获指定的信号并执行预定义的命令。

其基本的语法是:

trap 'command' signal

其中signal是要捕获的信号,command是捕获到指定的信号之后,所要执行的命令。

可以用kill l命令看到系统中全部可用的信号名,捕获信号后所执行的命令可以是任何一条或多条合法的shell语句,也可以是一个函数名。

shell脚本在执行时,会产生三个所谓的“伪信号”,之所以称之为“伪信号”是因为这三个信号是由shell产生的,而其它的信号是由操作系统产生的

表 1. shell伪信号

信号名 何时产生

EXIT 从一个函数中退出或整个脚本执行完毕

ERR     当一条命令返回非零状态时(代表命令执行不成功)

DEBUG 脚本中每一条命令执行之前

通过捕获EXIT信号,我们可以在shell脚本中止执行或从函数中退出时,输出某些想要跟踪的变量的值,并由此来判断脚本的执行状态以及出错原因,其使用方法是:

trap 'command' EXIT 或 trap 'command' 0

通过捕获ERR信号,我们可以方便的追踪执行不成功的命令或函数,并输出相关的调试信息,

以下是一个捕获ERR信号的示例程序,其中的$LINENO是一个shell的内置变量,代表shell脚本的当前行号。

$ cat -n exp1.sh

     1  ERRTRAP()

     2  {

     3    echo "[LINE:$1] Error: Command or function exited with status $?"

     4  }

     5  foo()

     6  {

     7    return 1;

     8  }

     9  trap 'ERRTRAP $LINENO' ERR

    10  abc

    11  foo

其输出结果如下:

$ sh exp1.sh

exp1.sh: line 10: abc: command not found

[LINE:10] Error: Command or function exited with status 127

[LINE:11] Error: Command or function exited with status 1

      

在调试过程中,为了跟踪某些变量的值,我们常常需要在shell脚本的许多地方插入相同的echo语句来打印相关变量的值,这种做法显得烦琐而笨拙。

而通过捕获DEBUG信号,我们只需要一条trap语句就可以完成对相关变量的全程跟踪。

以下是一个通过捕获DEBUG信号来跟踪变量的示例程序:

$ cat n exp2.sh

     1  #!/bin/bash

     2  trap 'echo before execute line:$LINENO, a=$a,b=$b,c=$c' DEBUG

     3  a=1

     4  if [ "$a" -eq 1 ]

     5  then

     6     b=2

     7  else

     8     b=1

     9  fi

    10  c=3

    11  echo "end"

其输出结果如下:

$ sh exp2.sh

before execute line:3, a=,b=,c=

before execute line:4, a=1,b=,c=

before execute line:6, a=1,b=,c=

before execute line:10, a=1,b=2,c=

before execute line:11, a=1,b=2,c=3

end

从运行结果中可以清晰的看到每执行一条命令之后,相关变量的值的变化。



eval

http://www.cnblogs.com/friedwm/archive/2012/04/06/2435171.html  

eval 相当于一个参数替换器,它会把所有 $开头的变量 进行求值替换,然后把替换后的结果当作一条命令来执行

#!/bin/bash

PARA="hello world my friend"

function Process()

{

  temp=$(eval echo \$$1 | cut -d ' ' -f 2-)      

  eval $1=\$temp  #2

}

Process PARA

echo $PARA

[oracle@ ~]$ sh tesh.sh
world my friend

说明:

#1eval先将它后面所有变量求值,$1==PARA,然后再执行 echo $PARA | cut -d ' ' -f 2-,得到处理后的值,临时存于temp

#2处,先进行替换,替换结果为: PARA=$temp,再执行这条命令,结果复制回源参数。

http://doudouclever.blog.163.com/blog/static/175112310201252111104169/  

set 11 22 33 44

如果要输出最近一个参数,即44,可以使用如下命令,

echo $4

但是如果我们不知道有几个参数的时候,要输出最后一个参数,大家可能会想到使用$#来输出最后一个参数,

如果使用命令:

echo "\$$#"

则得到的结果是 $4,而不是我们想要的44。这里涉及到一个变量间接引用的问题,我们的本意是输出 $4,默认情况下,命令后忽略变量间接引用的情况。

这时候,就可以使用eval命令。

eval echo "\$$#"

得到的结果为44



sourceexecsystem

http://www.cnblogs.com/zhaoyl/archive/2012/07/07/2580749.html   

bash shell的命令分为两类:外部命令和内部命令;

外部命令是通过系统调用或独立的程序实现的,如sedawk等等;

内部命令是由特殊的文件格式(.def)所实现,如cdhistoryexec等等。

有两种方法执行shell scripts,一种是新产生一个shell,然后执行相应的shell scripts;一种是在当前shell下执行,不再启用其他shell

新产生一个shell然后再执行scripts的方法是在scripts文件开头加入以下语句

#!/bin/sh

一般的script文件(.sh)即是这种用法。这种方法先启用新的sub-shell(新的子进程),然后在其下执行命令。

另外一种方法就是上面说过的source命令,不再产生新的shell,而在当前shell下执行一切命令。

source命令即点(.)命令。

bash下输入man source,找到source命令解释处,可以看到解释”Read and execute commands from filename in the current shell environment and …”。

从中可以知道,source命令是在当前进程中执行参数文件中的各个命令,而不是另起子进程(sub-shell)

exec:

bash下输入man exec,找到exec命令解释处,可以看到有”No new process is created.”这样的解释,这就是说exec命令不产生新的子进程。那么execsource的区别是什么呢?

1. 系统调用exec是以新的进程去代替原来的进程,但进程的PID保持不变。因此,可以这样认为,exec系统调用并没有创建新的进程,只是替换了原来进程上下文的内容。

原进程的代码段,数据段,堆栈段被新的进程所代替。

一个进程主要包括以下几个方面的内容:

(1)一个可以执行的程序

(2) 与进程相关联的全部数据(包括变量,内存,缓冲区)

(3)程序上下文(程序计数器PC,保存程序执行的位置

2. exec是一个函数簇,由6个函数组成,分别是以exclexecv打头的。

执行exec系统调用,一般都是这样,用fork()函数新建立一个进程,然后让进程去执行exec调用。

我们知道,在fork()建立新进程之后,父进各与子进程共享代码段,但数据空间是分开的,但父进程会把自己数据空间的内容copy到子进程中去,还有上下文也会copy到子进程中去。

而为了提高效率,采用一种写时copy的策略,即创建子进程的时候,并不copy父进程的地址空间,父子进程拥有共同的地址空间,

只有当子进程需要写入数据时(如向缓冲区写入数据),这时候会复制地址空间,复制缓冲区到子进程中去。从而父子进程拥有独立的地址空间。

而对于fork()之后执行exec后,这种策略能够很好的提高效率,如果一开始就copy,那么exec之后,子进程的数据会被放弃,被新的进程所代替。

3. execsystem的区别

(1) exec是直接用新的进程去代替原来的程序运行,运行完毕之后不回到原先的程序中去。

(2) system是调用shell执行你的命令,system=fork+exec+waitpid,执行完毕之后,回到原先的程序中去。继续执行下面的部分。

总之,如果你用exec调用,首先应该fork一个新的进程,然后exec. system不需要你fork新进程,已经封装好了。

exec命令在执行时会把当前的shell process关闭,然后换到后面的命令继续执行。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/15480802/viewspace-765230/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2010-03-18

  • 博文量
    375
  • 访问量
    3109381