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.

顺序 选择 循环 总结

原文地址:https://www.cnblogs.com/Braveliu/p/11013967.html