shell脚本58问
【1】交互方式、非交互方式、Shell脚本是什么?
经常与linux打交道,肯定对shell这个词不陌生。不明白shell意思的,可以自行翻译:外壳、去壳。
这个翻译结果怎么可以与计算机系统联系起来呢?看不懂?
为了帮助理解shell这个词,请看下图:
计算机系统,最内层(本质)的是硬件,然后硬件会被系统核心层包住,而在系统核心外层的就是所谓的shell,再然后shell外层的就是我们接触最多且最容易理解的应用程序。
shell其实是一个命令解释器,作用是解释用户输入的命令和程序,命令和程序可以理解成上图中的应用程序。
linux系统中的那些命令其实也都是一个个的小程序,只不过执行的是系统的应用功能。
当我们在系统的终端中输入一条命令,可以立马看到一条或者几条系统回复我们的信息,其实就是shell在帮我们回复,所以shell可以称之为命令解释器。
而这种从键盘一输入命令,就立马得到相应的回复信息,叫作交互的方式。
了解了shell之后,再来了解下shell脚本。如果我们的命令或应用程序不在命令行直接执行,而想通过一个程序文件来执行时,这个程序文件就被称之为shell脚本。
shell脚本里面通常内置了多条命令,有的还包含控制语句,比如if和else的条件控制语句,for的循环控制语句等。
这些内置在一个shell脚本中的命令通常是一次性执行完成,不会不停的返回信息给用户,这种通过文件执行脚本的方式称之为非交互方式。
shell脚本类似于windows下的批处理,但它比批处理要强大一些,现在windows下有一个叫做power shell的功能其实和linux下的shell功能媲美。
在文本中输入一系列的命令、控制语句和变量,这一切有机的结合起来就形成了功能强大的shell脚本。
日常工作中,经常需要使用多个命令来完成一项任务,可以添加这些所有命令在一个文本文件(Shell脚本)来统一完成这些日常工作任务。
【2】什么是默认登录shell,如何改变指定用户的登录shell?
登录shell是可以用户登录使用的,比如/bin/bash, /bin/sh, /bin/csh......
一般Linux默认的用户shell都是bash,也就是你可以登录进去写命令。
非登录shell:经典的/bin/nologin就是一个非登录shell,也就是说如果一个用户默认的是它,这个用户即使登录进linux也无法使用linux。
shell是用户和计算机交流的媒介,登录shell保证用户和计算机交流,非登录shell无法让计算机和用户交流。
关于用户的默认登录shell是在/etc/passwd文件中记录的。本地系统示例如下:
非登录shell有其特定的用途:比如一个用linux搭建的ftp服务器,创建了多个用户,可以将这些用户默认shell改成nologin。
这样一来,这些用户虽然是linux上的用户却无法登录进linux主机,只能进入ftp服务器,这样也保证了安全!
在Linux操作系统,“/bin/bash”是默认登录shell,是在创建用户时分配的。
使用chsh命令可以改变默认的shell。示例如下所示:
# chsh <用户名> -s <新shell>
# chsh zhangsan -s /bin/sh
当然,也可以直接通过修改/etc/passwd文件中对应用户的默认shell。
查看系统中有哪些shell,利用命令:cat /etc/shells
示例如下(本地系统中有六种shell):
【3】可以在shell脚本中使用哪些类型的变量?
在shell脚本,我们可以使用两种类型的变量:
(1)系统定义变量
(2)用户定义变量
系统变量是由系统系统自己创建的。这些变量通常由大写字母组成,可以通过“set”命令查看。
用户变量由系统用户来生成和定义,变量的值可以通过命令“echo $<变量名>”查看。
shell变量的作用域可以分为三种:
(1)有的变量只能在函数内部使用,叫做局部变量(local variable)
(2)有的变量可以在当前shell进程中使用,叫做全局变量(global variable)
(3)有的变量还可以在子进程中使用,叫做环境变量(environment variable)
【4】如何将标准输出和错误输出同时重定向到同一位置?
这个需求有两种方法可以实现:
(1)方法一:2>&1
示例:# ls /usr/share/doc > log.txt 2>&1
前半部分 ls /usr/share/doc > log.txt 很容易理解,那么后面的 2>&1 是怎么回事呢?
要解释这个问题,还得提到文件重定向。假定已经知道 > 和 < 是文件重定向符。那么1和2是什么?
在shell中,每个进程都和三个系统文件相关联:
(0)标准输入stdin
(1)标准输出stdout
(2)标准错误stderr
三个系统文件的文件描述符分别为0、1、2。所以,这里 2>&1 的意思就是将标准错误也输出到标准输出当中。
& 表示“等同于”的意思,2>&1,表示2的输出重定向等同于1。
实际上,> 就相当于 1> 也就是重定向标准输出,不包括标准错误。
而通过 2>&1 就将标准错误重定向到标准输出了(stderr已作为stdout的副本),那么再使用>重定向就会将标准输出和标准错误信息一同重定向了。
如果只想重定向标准错误到文件中,则可以使用 2> file。
(2)方法二:&>
示例:# ls /usr/share/doc &> log.txt
& 是一个描述符,如果1或2前不加&,会被当成一个普通文件。
1>&2 把标准输出重定向到标准错误。
2>&1 把标准错误输出重定向到标准输出。
&> filename 把标准输出和标准错误输出都重定向到文件filename中
摘录同问:Linux重定向中 >&2 怎么理解?
问题补充:echo "abdefghijklmn" >&2 怎么理解?
问题解答:>&2 即 1>&2 也就是把结果输出到和标准错误一样;之前如果有定义标准错误重定向到某log文件,那么标准输出也重定向到这个log文件。
如:ls 2>a1 >&2 (等同 ls >a1 2>&1)
把标准输出和标准错误都重定向到a1,终端上看不到任何输出信息。
【5】shell脚本中“if”语法如何嵌套?
基础语法如下:
if [ 条件 ]
then
命令1
命令2
…
else
if [ 条件 ]
then
命令1
命令2
…
else
命令1
命令2
…
fi
fi
if语法示例如下:
#!/bin/bash a=100 b=200 echo "a : "$a echo "b : "$b if [ $a == $b ] then echo "a 等于 b" elif [ $a -gt $b ] then echo "a 大于 b" elif [ $a -lt $b ] then echo "a 小于 b" else echo "没有符合的条件" fi
if语法输出结果:
a : 100
b : 200
a 小于 b
if嵌套语法示例如下:
#!/bin/bash a=100 b=200 echo "a : "$a echo "b : "$b if [ $a == $b ] then echo "a 等于 b" else if [ $a -gt $b ] then echo "a 大于 b" else if [ $a -lt $b ] then echo "a 小于 b" else echo "没有符合的条件" fi fi fi
if嵌套语法输出结果:
a : 100
b : 200
a 小于 b
【6】shell脚本中“$?”标记的用途是什么?
在写一个shell脚本时,若想要检查前一命令是否执行成功,在if条件中使用“$?”可以来检查前一命令的结束状态。
简单的例子如下:
如果结束状态是0,说明前一个命令执行成功。
如果结束状态不是0,说明命令执行失败。
【7】在shell脚本中如何比较两个数字?
在if-then中使用测试命令(-gt等)来比较两个数字。
-gt示例如下:
#!/bin/bash x=10 y=20 if [ $x -gt $y ] then echo "x is greater than y" else echo "y is greater than x" fi # 输出 # y is greater than x
test示例如下:
#!/bin/bash num1=$[2*3] num2=$[1+5] if test $[num1] -eq $[num2] then echo '两个数字相等!' else echo '两个数字不相等!' fi # 输出 # 两个数字相等!
【8】shell脚本中break命令的作用?
break命令一个简单的用途是退出执行中的循环。
可以在while和until循环中使用break命令跳出循环。
从while循环中跳出,示例如下:
#!/bin/bash a=0 while [ $a -lt 10 ] do echo $a a=`expr $a + 1` if [ $a -gt 8 ] then echo "break" break fi done # 输出 0 1 2 3 4 5 6 7 8 break
从until循环中跳出,示例如下:
#!/bin/bash a=0 until [ ! $a -lt 10 ] do echo $a a=`expr $a + 1` if [ $a -gt 8 ] then break fi done # 输出 0 1 2 3 4 5 6 7 8
从 for 循环中跳出,示例如下:
#!/bin/bash for loop in 1 2 3 4 5 do echo "The value is: $loop" if [ $loop == 4 ] then echo "break" break fi done # 输出 The value is: 1 The value is: 2 The value is: 3 The value is: 4 break
如上三种跳出方式。
【9】shell脚本中continue命令的作用?
continue命令不同于break命令,它只跳出当前循环的迭代,而不是整个循环。
continue命令很多时候是很有用的,例如错误发生,但我们依然希望继续执行大循环的时候。
示例如下:
#!/bin/bash for i in `seq 1 5` do echo $i if [ $i == 3 ] then continue fi echo $i done echo $i # 输出 1 1 2 2 3 4 4 5 5 5
如上示例。
【10】shell脚本中case语句的语法?
基础语法如下:
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
esac
case语法示例如下(用vim 新建文件cash.sh,输入内容):
#!/bin/bash echo '输入 1 到 4 之间的数字:' echo '你输入的数字为:' read aNum case $aNum in 1) echo '你选择了 1' ;; 2) echo '你选择了 2' ;; 3) echo '你选择了 3' ;; 4) echo '你选择了 4' ;; *) echo '你没有输入 1 到 4 之间的数字' ;; esac
如上脚本,执行./case.sh 或 sh case.sh
【11】shell脚本中while循环语法?
如同for循环,while循环只要条件成立就重复它的命令块。
不同于for循环,while循环会不断迭代,直到它的条件不为真。
基础语法:
while [ 条件 ]
do
命令…
done
【12】如何使脚本可执行?
使用chmod命令来使脚本可执行。示例如下:
# chmod a+x myshell.sh
【13】“#!/bin/bash”的作用?
#!/bin/bash是shell脚本的第一行,称为释伴(shebang)行。
这里#符号叫做hash,而!叫做bang。它的意思是命令通过 /bin/bash 来执行。
【14】shell脚本中for循环语法?
for循环的基础语法:
for 变量 in 循环列表
do
命令1
命令2
…
最后命令
done
【15】如何调试shell脚本?
两种方式:
(1)使用‘-x’参数(sh -x myshell.sh)可以调试shell脚本。
如上面例子中的case.sh脚本,调试结果如下:
如上。
(2)使用‘-xv’参数,但是,写法与第一种不同,具体如下:
#!/bin/bash -xv
应用示例如下:
#!/bin/bash -xv echo '输入 1 到 4 之间的数字:' echo '你输入的数字为:' read aNum case $aNum in 1) echo '你选择了 1' ;; 2) echo '你选择了 2' ;; 3) echo '你选择了 3' ;; 4) echo '你选择了 4' ;; *) echo '你没有输入 1 到 4 之间的数字' ;; esac
输出结果:
如上。
【16】shell脚本如何比较字符串?
test命令可以用来比较字符串。测试命令会通过比较字符串中的每一个字符来比较。
参数 说明
= 等于则为真
!= 不相等则为真
-z 字符串 字符串的长度为零则为真
-n 字符串 字符串的长度不为零则为真
示例如下(用vim新建test.sh文件,输入如下内容):
#!/bin/bash num1="abcdef" num2="abcdefg" if test $num1 = $num2 then echo '两个字符串相等!' else echo '两个字符串不相等!' fi if test $num1 != $num2 then echo '两个字符串不相等!' else echo '两个字符串相等!' fi if test -z "$num1" then echo 'num1字符串长度为0' else echo 'num1字符串长度不为0' fi num2= if test -n "$num2" then echo 'num2字符串长度不为0' else echo 'num2字符串长度为0' fi # 输出 # 两个字符串不相等! # 两个字符串不相等! # num1字符串长度不为0 # num2字符串长度为0
如上内容。
【17】Bourne shell(bash) 中有哪些特殊的变量?
下面的表列出了Bourne shell为命令行设置的特殊变量。
内建变量 解释
$0 当前脚本的文件名
$n 传递给脚本或函数的参数。n是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。
$# 传递给脚本或函数的参数个数。
$* 传递给脚本或函数的所有参数。
$@ 传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同。可参见下文第【26】问。
$$ 当前shell进程ID。对于shell脚本,就是这些脚本所在的进程ID。
示例如下:
#!/bin/bash echo "0:$0" echo "1:$1" echo "2:$2" echo "3:$3" echo "4:$4" echo "5:$5" echo "6:$6" echo "7:$7" echo "8:$8" echo "9:$9" echo "#:$#" echo "*:$*" echo "@:$@" echo "$:$$"
输出结果:
如上过程。
【18】在shell脚本中,如何测试文件?
test命令可以用来测试文件。
test命令基础用法如下表格:
test 用法
-d 文件名 如果文件存在并且是目录,返回true
-e 文件名 如果文件存在,返回true
-f 文件名 如果文件存在并且是普通文件,返回true
-r 文件名 如果文件存在并可读,返回true
-s 文件名 如果文件存在并且不为空,返回true
-w 文件名 如果文件存在并可写,返回true
-x 文件名 如果文件存在并可执行,返回true
示例如下:
#!/bin/bash if test -e ./shellarg.sh then echo '文件已存在!' else echo '文件不存在!' fi
输出结果:
如上。
【19】在shell脚本中,如何写入注释?
注释可以用来描述一个脚本可以做什么和它是如何工作的。每一行注释以#开头。
示例如下:
#!/bin/bash
# This is a command
【20】如何让shell脚本得到来自终端的输入?
read命令可以读取来自终端(使用键盘)的数据。read命令得到用户的输入并置于你给出的变量中。
示例如下:
#!/bin/bash echo ‘please enter your name’ read name echo “my Name is $name”
输出结果:
如上。
【21】如何取消变量或取消变量赋值?
“unset”命令用于取消变量或取消变量赋值。
语法如下所示:
unset [-fv] [变量或函数名称]
-f:仅删除函数
-v:仅删除变量
应用示例如下:
#!/bin/bash export JAVA_HOME=/usr/local/jdk echo $JAVA_HOME unset JAVA_HOME echo $JAVA_HOME a=100 readonly PI=3.141592653 function func() { echo 'call fun()' } echo 'unset a' unset a func echo 'unset func' unset func echo 'unset PI' unset PI
输出结果:
注意:unset 删除不了只读变量
如上
【22】如何执行算术运算?
有两种方法来执行算术运算:
1.使用expr命令
# expr 5 + 2
2.用一个美元符号和方括号($[ 表达式 ])
例如:
test=$[16 + 4]
示例如下:
#!/bin/bash a=2 b=3 result1=$[a + b] result2=`expr $a + $b` echo "result1:$result1" echo "result2:$result2"
输出结果:
如上。
【23】在shell脚本如何定义函数呢?
函数是拥有名字的代码块。
当我们定义代码块,我们就可以在我们的脚本调用函数名字,该块就会被执行。示例如下所示:
$ diskusage () { df -h ; }
译注:下面是我给的shell函数语法,原文没有
[ function ] 函数名 [()]
{
命令;
[return int;]
}
示例如下:
#!/bin/bash function demoFunc() { echo "这是我的第一个shell函数!" } echo "-----函数开始执行-----" demoFunc echo "-----函数执行完毕-----"
输出结果:
如上。
【24】shell脚本中如何退出?
利用exit退出整个脚本。
示例如下:
#!/bin/bash for i in `seq 1 5` do echo $i if [ $i == 3 ] then echo "exit" exit fi echo $i done echo "end" # 输出 1 1 2 2 3 exit
如上示例。
【25】shell中如何判断字符串为空?
利用test命令,上面有讲过。
也可以如下示例:
#!/bin/bash string= if [ -z "$string" ]; then echo "string is empty" fi if [ -n "$string" ]; then echo "string is not empty" fi
输出结果:
如上
【26】Shell脚本“$*”和“$@”的联系是什么?
(1)相同点:都是引用所有参数。
(2)不同点:只有在双引号中体现出来。
假设在脚本运行时写了三个参数 1、2、3,则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)。
(3)示例
3.1 示例如下(利用vim新建脚本文件difference.sh,输出如下内容):
#!/bin/bash echo "-- \$* 演示 ---" for value in "$*"; do echo $value done echo "-- \$@ 演示 ---" for value in "$@"; do echo $value done
3.2 输出结果:
如上
【27】shell 如何实现定时执行任务?
定时器可以直接利用:/bin/sleep 时间(s)
示例如下:
#!/bin/bash echo "timer invite" count=0 while [ true ]; do # 定时器 1s /bin/sleep 1 count=$[count + 1] echo "invite:$count" done
输出结果:
如上。
【28】如何向脚本传递参数?
不懂shell的同事,可能不会修改shell代码(比如测试的妹子)。
那么,为了让脚本更通用,某些变量值需要在执行脚本时传入即可。
因某种需要,想在脚本执行时传入运行过程中的需要的参数。
示例如下(用vim新建文件argument.sh,输入如下内容):
#!/bin/bash echo "第一个参数值:$1" echo "第二个参数值:$2"
输出结果:
如上
【29】shell脚本如何读取文件?
工作中,最常用的就是利用shell脚本读取文件(比如日志文件log)。
shell脚本读取(read)文件,利用循环逐行进行读取。
示例如下:
#!/bin/bash echo "-------begin read file" while read -r line do echo $line done < $1 echo "-------end read file"
输出结果:
如上。注意:利用上一问的脚本传参方式将文件名作为参数传入。
【30】如何获取一个文件每一行的第三个元素?
使用 awk '{print $3}'
应用示例如下:
#!/bin/bash echo "-------begin read file content" while read -r line do echo $line done < $1 echo "-------end read file content" echo "---------begin read three column" awk '{print $3}' $1 echo "---------end read three column"
输出结果:
如上。
如何获取一个文件每一行的第三个元素 ?
作者:IT程序狮
链接:http://www.imooc.com/article/1131
来源:慕课网
【31】如何获取文件的第一行和最后一行内容?
获取首行:head -1
获取尾行:tail -1
应用示例如下:
#!/bin/bash echo "------begin read file content" while read -r line do echo $line done < $1 echo "------end read file content" echo "------begin read head line" head -1 $1 echo "------end read head line" echo "------begin read tail line" tail -1 $1 echo "------end read tail line"
输出结果:
如上。
【32】假如文件中某一行的第三个元素是18,如何获取第四个元素?
使用:awk '{ if ($3 == "18") print $4}'
应用示例如下:
#!/bin/bash echo "-------begin read file content" while read -r line do echo $line done < $1 echo "-------end read file content" echo "------begin four column value" awk '{ if ($3 == "18") print $4}' $1 echo "------end four column value"
输出结果:
如上。
【33】如何连接两个字符串?
应用示例如下:
#!/bin/bash v1="bei" v2="jing" echo "------字符串连接前" echo "v1:$v1" echo "v2:$v2" echo "------字符串连接方式一后" v3=${v1}${v2} echo "v3:$v3" echo "------字符串连接方式二后" echo "$v1$v2"
输出结果:
如上。
【34】shell脚本中如何进行两数相加?
方式共有六种。
应用示例如下:
#!/bin/bash A=5 B=6 echo "------原数据" echo "A:$A" echo "B:$B" echo "------方式一" let C=$A+$B echo $C echo "------方式二" echo $(($A+$B)) echo "------方式三" echo $[$A+$B] echo "------方式四" expr $A + $B echo "------方式五" echo $A+$B | bc echo "------方式六" awk 'BEGIN{print '"$A"'+'"$B"'}'
输出结果:
如上。
【35】每个脚本开始的 #!/bin/sh 或 #!/bin/bash 表示什么意思?
这一行说明要使用的 shell。#!/bin/bash 表示脚本使用 /bin/bash。对于 python 脚本,就是 #!/usr/bin/python。
【36】如何获取文本文件的第2行?
使用:head -2 file | tail -1
示例应用如下:
#!/bin/bash echo "------begin read file content" while read -r line do echo $line done < $1 echo "------end read file content" echo "------begin read second line" head -2 $1 | tail -1 echo "------end read second line"
输出结果:
如上。
【37】bash脚本文件的第一个符号是什么?
答:#
【38】命令:[ -z "" ] && echo 0 || echo 1 的输出是什么?
关于“-z” 可参考上面第15问理解:字符串长度为零则为真
关于&& 和 ||,即分别为shell脚本的逻辑运算符AND 和 OR
所以,[ -z "" ] 的值为真,那么:[ -z "" ] && echo 0 输出结果即为:0
示例如下:
#!/bin/bash echo " expression result" [ -z "" ] && echo 0 || echo 1 echo "end" echo "逻辑运算符演示" a=10 b=20 if [[ $a -lt 100 && $b -gt 100 ]] then echo "返回 true" else echo "返回 false" fi if [[ $a -lt 100 || $b -gt 100 ]] then echo "返回 true" else echo "返回 false" fi
输出结果:
如上。
【39】命令 “export” 有什么用?
使父shell定义的变量在子shell进程中可以使用。
用户登录到linux系统后,系统将启动一个用户shell。
在这个shell中,可以使用shell命令或声明变量,也可以创建并运行shell脚本程序。当运行shell脚本程序时,系统将创建一个子shell。
此时,系统中将有两个shell,一个是登录时系统启动的shell,另一个是系统为运行脚本程序创建的shell。
当一个脚本程序运行完毕,脚本shell(即子shell)将终止,返回到执行该脚本之前的shell。
从这种意义上来说,用户可以有许多shell,每个shell都是由某个shell(称为父shell)生的。
在子shell中定义的变量只在该子shell内有效。
即在一个shell脚本程序中定义了一个变量,当该脚本程序运行时,这个定义的变量只是该脚本程序内的一个局部变量,其他的shell不能引用它。
如果要使某个变量的值可以在其他shell中被改变,可以使用export命令对已定义的变量进行输出。
export命令将使系统在创建每一个新的shell时,定义这个变量的一个拷贝。这个过程称之为变量输出。
(1)修改生效范围
脚本A中export的变量在启动其他脚本时会复制一份传入其他脚本。其他脚本中对此变量的修改并不会在离开脚本后生效。
(2)注意
在脚本A中定义了一个变量V赋值为1,export了变量V,在脚本A中启动脚本B,在脚本B中变量V的值就是1,如果在脚本B中修改了V的值为2,那么脚本B结束后,脚本A中的V的值依然是1。
脚本A中export的变量在启动其他脚本的时候会复制一份传入其他脚本,传入的值是调用其他脚本时的值。并不是export时的值。
在脚本A中定义了一个变量V赋值为1,export了变量V,然后修改V为2,在脚本A中启动脚本B,在脚本B中变量V的值就是2。
应用示例如下:
使用vim创建脚本文件export_b.sh,输入如下内容:
#!/bin/bash echo "exec export_b start" A="this is export_b A" export B="this is export_b B" ./export_a.sh echo "export_b A:$A" echo "export_b B:$B" echo "exec export_b over"
使用vim创建脚本文件export_a.sh,输入如下内容:
#!/bin/bash echo "exec export_a start" echo "this is export_a, A=\"$A\"" echo "this is export_a, B=\"$B\"" A="this is export_a A" B="this is export_b B" echo "exec export_a over" exit 0
输出结果:
如上。
【40】如何在后台运行脚本?
主要分为以下三种需求场景:
(1)前台转后台运行脚本
[1] 执行脚本backrun.sh:./backrun.sh
[2] 中断脚本backrun.sh:ctrl+c
[3] 在[1]的基础上将运行中的backrun.sh,切换到后台并暂停:ctrl + z
[4] 执行ctrl + z 后,backrun.sh在后台是暂停状态(stopped)。
使用命令:bg number让其在后台开始运行(“number”是使用jobs命令查到的[ ]中的数字,不是pid)
(2)后台转前台运行脚本
[1] 直接在后台运行脚本backrun.sh:./backrun.sh &
[2] 查看当前shell环境中已启动的任务情况:jobs
[3] 将backrun.sh切换到前台运行:fg %number(”number”为使用jobs命令查看到的[ ]中的数字,不是pid)
[4] 中断后台运行的backrun.sh脚本:先fg %number切换到前台,再ctrl+c;或直接kill %number
尤其注意:以上两种在后台运行backrun.sh的方法,当遇到退出当前shell终端时,后台运行的backrun.sh也就结束了。为什么呢?
因为以上两种方法之所以使得backrun.sh在后台运行,运行backrun.sh进程的父进程是当前shell终端进程,关闭当前shell终端时,父进程退出,会发送hangup信号给所有子进程,子进程收到hangup以后也会退出。
所以要想退出当前shell终端时backrun.sh继续运行,则有两种方式:
方式一:使用nohup忽略hangup信号
[1] 不中断的在后台运行backrun.sh:nohup ./backrun.sh &(backrun.sh的打印信息会输出到当前目录下的nohup.out中)
[2] 使用jobs可看到backrun.sh处于running状态
[3] 使用ps -ef | grep backrun.sh可查看到正在运行的backrun.sh脚本进程
[4] 退出当前shell终端,再重新打开,使用jobs看不到正在运行的backrun.sh,但使用ps -ef可以看到
方式二:使用setsid将其父进程改为init进程(进程号为1)
[1] 不中断的在后台运行backrun.sh另一个命令:setsid ./backrun.sh &
[2] 使用ps -ef | grep backrun.sh可看到backrun.sh进程的父进程id为1
示例脚本程序如下:
#!/bin/bash count=1 while (( $count <= 100 )) do echo $count let "count++" sleep 1 done
自己运行体会。
【41】"chmod 500 myscript.sh" 做什么?
使脚本所有者拥有可执行权限。
对于Linux系统中的文件来说,有三种身份和四种权限,三种身份是:
u:文件的拥有者
g:文件所属的群组
o:其他用户
对于每个身份,又有四种权限,分别为:
r:读取文件的权限(read)
w:写入文件的权限(write)
x:执行的权限(execute)
s:特殊权限
说这么多,那500又是怎么回事呢?这其实也是Linux系统下一种表示文件权限的方式:
在Linux系统中,对于文件的权限有读取、写入、执行三种,分别用rwx表示,另一种表示权限的方式就是使用数字,读取、写入和执行权限分别由数字4、2和1表示:
读取权限:r 或者4
写入权限:w 或者2
执行权限:x 或者1
如下图:
那么,对于此例中的文件,用数字形式表示其权限的话,则为500,如下所示:
如上。
【42】">" 和 ">>" 做什么?
重定向输出流到文件或另一个流。
两者的区别:
(1)> :如果文件不存在,会创建文件。如果文件存在,就将其清空。即会重写文件,如果文件里面有内容会覆盖。
(2)>> :如果文件不存在,会创建文件。如果文件存在,将输出内容追加到目标文件中。
示例如下(为了便于演示,只演示>>的场景。利用上问的脚本):
#!/bin/bash count=1 while (( $count <= 100 )) do echo $count >> backrun.log let "count++" sleep 1 done
输出结果:
注意:
因为输出重定向到日志文件backrun.log文件中,所以启动脚本后,shell端看不到输入内容。
只能通过浏览backrun.log文件查看执行结果。
如上。
【43】“&”、“&&”和“;”有什么区别?
& :希望脚本在后台运行的时候使用它
&& :当前面的脚本执行成功后,才执行后面的脚本或命令
;:不管前面的脚本命令执行成功与否,后面的脚本或命令继续执行
如下三种形式:
1.command1 & command2 & command3
表示:三个命令同时执行
2.command1; command2; command3
表示:不管前面命令执行成功没有,后面的命令继续执行
3.command1 && command2
表示:只有前面命令执行成功,后面命令才继续执行
利用上问的脚本command1.sh,改造如下(从1开始计数):
#!/bin/bash count=1 while (( $count <= 100 )) do echo $count let "count++" sleep 1 done
command2.sh,改造如下(从100开始计数):
#!/bin/bash count=100 while (( $count <= 1000 )) do echo $count let "count++" sleep 1 done
command3.sh,改造如下(从1000开始计数):
#!/bin/bash count=1000 while (( $count <= 10000 )) do echo $count let "count++" sleep 1 done
执行命令command4.sh,内容如下(可尝试修改三种方式运行观察):
#!/bin/bash ./command1.sh & ./command2.sh & ./command3.sh
自己摸索体会其差异点。
【44】 ' 和 " 引号有什么区别?
' - 当我们不希望把变量转换为值的时候使用它。
” - 会计算所有变量的值并用值代替。
应用示例如下:
#!/bin/bash name=John && echo "My name is $name" age=18 && echo 'My age is $age'
输出结果:
如上。
【45】如何只用echo命令获取字符串变量的一部分?
应用示例如下:
#!/bin/bash echo "----按索引截取" variable="My name is wangjun, and I am developer" echo ${variable:11:7} localpath="User:192.168.1.15:/home/wangjun" echo "----截取尾部方式一:" echo ${localpath#*:*.*.*.*:} echo "----截取尾部方式二:" echo ${localpath##*:} echo "----截取头部方式一:" echo ${localpath%:*.*.*.*} echo "----截取头部方式二:" echo ${localpath%%:*} echo "----截取中间字符串" data=`echo ${localpath#*User:}` ip=`echo ${data%:/home*}` echo "${ip}"
输出结果:
如上。
【46】如何获取变量长度且获取变量最后10个字符?
应用示例如下:
#!/bin/bash value="abcdefghijklmnopqrstuvwxyz" echo "value length:${#value}" if [ ${#value} -gt 10 ] then echo "print tail 10:" echo ${value: -10} fi
输出结果:
如上。
【47】${variable:-10} 和 ${variable: -10} 有什么区别?
应用示例如下:
#!/bin/bash variable= echo ${variable:-10} echo ${variable: -10} variable="abcdefghijklmn" echo ${variable:-10} echo ${variable: -10}
输出结果:
总结:
${variable:-10} :如果之前没有给 variable 赋值则输出10;如果有赋值则输出该变量。
${variable: -10}:输出variable的最后10个字符。
如上。
【48】如何只用echo命令替换字符串的一部分?
示例如下:
#!/bin/bash variable="abcdefghijklmn" echo "方式一:${variable//def/wangqi}" echo 方式二:${variable//def/wangqi}
输出结果:
如上。利用echo ${variable//pattern/replacement}进行替换操作。
【49】如何将文本文件中的小写字符转换为大写?
tr [:lower:] [:upper:]
应用示例如下:
#!/bin/bash cat $1 | tr [:lower:] [:upper:]
输出结果:
如上。
【50】如何列出第二个字母是a 或 b的文件?
ls -d ?[ab]*
应用示例,输出结果:
如上。
【51】如何去除字符串中的所有空格?
echo $string | tr -d " "
应用示例如下:
#!/bin/bash var="I am wang qi and my age is 18." echo "var:$var" echo $var | tr -d " "
输出结果:
如上。
【52】重写这个命令,将输出变量转换为复数: item="car"; echo "I like $item" ?
重写脚本如下:
#!/bin/bash item="car" echo "I like ${item}s"
输出结果:
如上。
【53】写出输出数字 0 到 20 中 3 的倍数(0 3 6 9 …)的命令?
脚本如下:
#!/bin/bash echo "方式一:" for i in {0..20..3}; do echo $i done echo "方式二:" for (( i=0; i<20; i=i+3)); do echo "Welcome $i times" done
输出结果:
如上。
【54】[ $a == $b ] 和 [ $a -eq $b ] 有什么区别?
[ $a == $b ] - 用于字符串比较
[ $a -eq $b ] - 用于数字比较
【55】[[ $string == abc* ]] 和 [[ $string == "abc" ]] 有什么区别?
[[ $string == abc* ]] - 检查字符串是否以字母 abc 开头
[[ $string == "abc" ]] - 检查字符串是否完全等于 abc
应用示例如下:
#!/bin/bash string="abcdefhigk" if [[ $string == abc* ]] ; then echo "string is start with abc" else echo "string is not start with abc" fi if [[ $string == "abc" ]] ; then echo "string is abc" else echo "string is not abc" fi
输出结果:
如上。
【56】如何打印数组中的所有元素?
应用示例如下:
#!/bin/bash array=("Hi" "my" "name" "is") echo "打印数组第一个元素" echo ${array[0]} echo "打印数组的所有元素" echo ${array[@]} echo "输出所有数组索引" echo ${!array[@]} echo "移除数组中索引为2的元素" unset array[2] echo ${array[@]} echo "在数组中添加id为110的元素" array[110]="new_element_110" echo ${array[@]}
输出结果:
如上。
【57】不用 wc 命令如何计算字符串中的单词数目?
应用示例如下:
#!/bin/bash string="my name is wang qi and my age is 18" echo $string set ${string} echo count:$#
输出结果:
如上。
【58】shell脚本如何进行数据库操作?
以mysql数据库为例。不用在mysql的提示符下运行mysql,在shell脚本中操作mysql的方法:
mysql -hhostname -Pport -uusername -ppassword -e 执行的sql语句
应用示例如下:
#!/bin/bash HOSTNAME="119.254.95.194" PORT="3306" USERNAME="root" PASSWORD="123456" use_sql="use billing;" mysql -h${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} -e "${use_sql}" select_sql="use billing; select * from cfg_dict into outfile '/var/lib/mysql/cfg_dict.csv' fields terminated by ',';" mysql -h${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} -e "${select_sql}"
如上。
【59】待续....
Good Good Study, Day Day Up.
顺序 选择 循环 总结