共计 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 知识点有哪些”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!