shell知识点有哪些

72次阅读
没有评论

共计 6383 个字符,预计需要花费 16 分钟才能阅读完成。

这篇文章给大家分享的是有关 shell 知识点有哪些的内容。丸趣 TV 小编觉得挺实用的,因此分享给大家做个参考,一起跟随丸趣 TV 小编过来看看吧。

$?  前一命令退出状态,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 表明选项 a、h、f、v 可以不加实际值进行传递,而选项 c 必须取值。使用选项取值时,必须使用变量 OPTARG 保存该值。

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

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

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

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

option is i,the value is 1

option is I

option is v \n

(2)sh datediff.sh -s -i 1

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

(3)sh 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-) #1 

eval $1=\$temp #2

}

Process PARA

echo $PARA

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

说明:

#1 处 eval 先将它后面所有变量求值,$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

source、exec 与 system

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

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

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

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

有两种方法执行 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 命令不产生新的子进程。那么 exec 与 source 的区别是什么呢?

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

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

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

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

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

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

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

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

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

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

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

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

3. exec 与 system 的区别

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

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

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

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

感谢各位的阅读!关于“shell 知识点有哪些”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-16发表,共计6383字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)