当前位置:首页 > 实时新闻 > 正文

shell 操作

摘要: shell操作最佳答案53678位专家为你答疑解惑shell操作shell的三种运行方式1.#shfilename(子进程运行,...

shell 操作

最佳答案 53678位专家为你答疑解惑

shell 操作

shell的三种运行方式1.#sh filename

(子进程运行,结束后变量名失效)

2. #./filename

(子进程运行,结束后变量名失效)

3.source filename

(父进程运行,结束后变量名有效)

0.变量
var=0echo $varecho ${var}  #加大括号是为了帮助解释器识别变量的边界readonly var  #var变成了只读变量
字符串
str='2333 333' #单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;#单引号字串中不能出现单引号(对单引号使用转义符后也不行)。
name='glassy'str="my name is  \"$your_name\"! \n" #可以有变量可以转义

拼接字符串

str1="hello,"str2="world"echo $str1$str2
$var=0$var
1.if-else
if conditionthen    command1     command2    ...    commandN fi
if conditionthen    command1     command2    ...    commandN fi
if condition1then    command1elif condition2 then     command2else    commandNfi
2.for
for var in item1 item2 ... itemNdo    command1    command2    ...    commandNdone

例子:

for i in {1..10}do   mkdir glassy$idone
3.while
while conditiondo    commanddone

万字总结 | 完全掌握Shell编程

对于Linux平台下的开发者和维护人员来说,Shell编程是必须要掌握的一个知识点。通过Shell脚本能够将十分复杂的操作进行简化,从而大大的提高我们工作效率。

什么是Shell?

实际上,Shell是一个比较宽泛的概念,它可以有多种含义。比如,一个终端或命令行软件我们可以称为Shell,实际上它就是一个应用程序,是人与系统进行交互的一个操作界面;它也是一种程序语言或者命令语言,可以通过它编译一系列的脚本。

作为Shell终端软件来说,它实际上也是属于泛指。之所以这么说是因为Shell终端软件也有多种。不过,基本上所有的Linux和大多数的Mac OS X里默认用的都是Bourne Again Shell,也就是平时我们说的bash。它早在1987年由Brian Fox开发。

除bash之外,还有其他的Shell应用程序:

Shell应用程序

然而,今天我们要学习的实际上是在Shell上执行的脚本语言,所以我们说Shell脚本编程。由于它是一种解释性语言,Shell脚本编程不需要额外的安装编译器,它可以直接用编辑器直接编辑,然后直接在Shell上直接运行即可。通常,我们在编写脚本时,在第一行需要用#!来指定解释器来运行Shell脚本,比如,#!/bin/sh。

下面我们将为大家从如下几个方面全面系统的为大家梳理Shell编程的相关知识点。

Shell编程

输入输出

shell中有两种输出命令:echo和printf。学习程序,生硬的文字始终没有代码来的直接易懂。我们就直接通过例子来学习吧。

echo "hello world"printf "%s %s" "hello" "world"printf "!!!\n"

output

从上面的例子很容易发现,echo命令默认带有换行符的,而printf则不是。与C语言中类似,printf是可以进行格式化输出的,其中,%s就是格式控制符,还有%c %d %f等控制符。另外,还可以通过在控制符中添加数字来制定字符的长度,比如,%3s表示三个字符长度;%4.3f表示4位整数,3位小数。

#!/bin/shprintf "%6s %3s %4s %5s\n" 公司名 评级 销售额 市场占比printf "%6s %3c %4d %5f\n" 公司A A 5001 0.5001printf "%6s %3c %4d %5f\n" 公司B C 1999 0.1999printf "%6s %3c %4d %5f\n" 公司B B 3000 0.3

printf

如果需要字符对齐,还可以使用-进行字符左对齐,省略不加默认右对齐。

在shell中是使用read命令作为输入,它可以接受标准键盘的输入;除此之外,也可以作为文件描述符的输入,对文件进行操作。

read命名的格式如下:

read [选项名] [变量名]

read命令在执行时,会将输入的数据放到变量中,通常,我们会指定一个自定义的变量,如果不指定变量的话,则就会把输入的数据保存到REPLY变量中。关于变量的一些具体信息可以在下面的变量章节了解。

read命令的选项名有下面几种参数,我们可以选择一种或几种进行设置。

-p:设置提示信息,屏幕会输出提示信息;-t:设置等待时间(秒),等待用户输入的时间;-n:设置接收指定的字符数;-s:隐藏输入的数据,用于比较隐私机密信息的输入。

具体的使用方法大家可以参考下面的例子:

#!/bin/shread -p "input a name:" nameread -p "input a password:" -s passwdecho ""echo $nameecho $passwd

read

注释

每种语言都少不了注释,对于Shell也是一样。一个好的注释可以让代码更容易阅读和维护。shell脚本里也可以使用两种注释:单行注释和多行注释。单行注释可以直接在所在行使用#,多行注释就需要:<<!和!。

# 这是一行内容# 这是一行内容:<<!这是一行内容这是一行内容!

对于多行注释除了用!符号外,还可以用EOF '等符号。

除了这两种方法之外,还可以通过条件语句来实现。

变量

Shell可以定义变量,并通过=给变量赋值,与其他语言不同的是,在=和变量及被赋的值之间不能有空格。习惯了其他语言的同学可能会有些不适应,不过要注意这一点。

对于命名的规则,其实是与其他语言是类似的:

使用英文字母,数字和下划线,但不能以数字开头。shell的保留关键字不可以使用
v1=1234 #正确v2="hello" #正确v3_1="world" #正确v4_1="world" #错误,‘=’符前后不能有空格

除此之外,在访问变量时需要在变量前$符来访问,如果需要区分变量的边界,还需要在变量前后加上{}用来区分变量名的边界,建议在使用变量时加上{}。

a="hell world:"b="一个敲代码的厨子"echo ${a}${b}

Shell的数据类型比较简单,变量的默认数据类型是字符串类型。我们可以使用单引号或双引号,因此,也是可以不用引号的。

我们再来看一个例子:

a=1b=2echo ${a}+${b}

大家觉得最后应该输出多少呢?

答案是不是超出了大家的预料?这样大家应该理解了为什么说Shell定义变量时默认是字符串类型。

那么问题来了,该怎么表示数字呢?其实,这里我们稍微进行特殊处理一下就可以了,在数据运算的时候我们用$[运算表达式]形式就可以了。

a=1b=2echo $[${a}+${b}]

a+b

除了这种方法,还有其他的方法可以进行数据运算,我们在后面的数据运算章节在详细展开,我们接着说变量。

我们可以将变量分成局部变量和环境变量:

局部变量:是在Shell命令或脚本中定义的变量,只能在当前Shell命令或脚本中有效。环境变量:创建它们的shell及其派生出来的任意子进程中使用等。它可以保证一些程序的正常运行。

在一些特殊的场景,我们不希望我们定义的变量数值被改变,这时,我们可以使用readonly命令将变量设置成只读。

a="hello world"readonly aecho ${a}a="hahah"

还有一些场景需要清除一个变量,我们可以使用unset命令将变量删除,需要注意的是对于只读变量是不能删除的。

a="hello world"b="一个敲代码的厨子"readonly bunset aunset becho ${a}echo ${b}

字符串变量操作

了解了上面变量的内容之后,我们知道变量模式是字符串类型的。那字符串的操作有哪些呢?

一般我们可以会对字符串变量进行如下操作:

获取字符串的长度:可以变量前加上#符号,${#变量};截取字符串:可以在变量后使用:截取,${变量:x:y};替换字符串中子字符串:可以在变量后使用/符号,${变量/子字符串/替换的字符串};删除字符串中的子字符串:实际上可以通过替换子字符串的方法实现;字符串大小写替换:可以使用^^转换成大写,使用,,转换成小写;

下面,我们可以从下面的例子更直观的了解这些操作。

a="Hello World"echo "${#a}" #获取字符串长度echo "${a:6:3}" #从下标6开始截取3字符echo "${a/ll/hh}" #将字符串中的ll替换为hhecho "${a/or/}" #删除子字符串orecho "${a^^}" #全部转化成大写echo "${a,,}" #全部转化成小写

字符串操作

数字运算

在上面的变量章节,我们学习到了可以使用$[运算表达式]形式,使数字变量进行运算。这一章节,我们将会详细了解数字运算。实际上Shell可以使用命令和运算表达式的方式进行数字运算,它们可以支持+ - * / %等算术运算。

命令方式主要有let declare expr等命令,下面我们一一通过例子来学习他们的使用。

通过let命令进行数字运算,let命名后直接跟上运算表达式即可。

#!/bin/sha="4"b="2"let c1=${a}+${b}let c2=${a}-${b}let c3=${a}*${b}let c4=${a}/${b}let c5=${a}%${b}echo "a + b=" ${c1}echo "a - b=" ${c2}echo "a * b=" ${c3}echo "a / b=" ${c4}echo "a % b=" ${c5}

let命令

通过expr命令进行数字运算,可以查看下面的示例代码,但是需要注意两点:

运算符和两边的变量需要使用空格隔开;需要注意需要将*转义为\*。
#!/bin/sha=4b=2c1=$(expr ${a} + ${b})echo "a + b=" ${c1}c2=$(expr ${a} - ${b})echo "a - b=" ${c2}c3=$(expr ${a} \* ${b})echo "a * b=" ${c3}c4=$(expr ${a} / ${b})echo "a / b=" ${c4}c5=$(expr ${a} % ${b})echo "a % b=" ${c5}

expr

declare命令也可以进行数字运算,它的参数选项中有一个-i选项,它可以将变量声明为整数型,因此,我们也可以通过declare实现数字的运算。

#!/bin/sha="4"b="2"declare -i c1=${a}+${b}declare -i c2=${a}-${b}declare -i c3=${a}*${b}declare -i c4=${a}/${b}declare -i c5=${a}%${b}echo "a + b=" ${c1}echo "a - b=" ${c2}echo "a * b=" ${c3}echo "a / b=" ${c4}echo "a % b=" ${c5}

declare命令 declare命令

通过运算表达式实现数字运算的方式,主要有$((运算表达式))和$[运算表达式],我们依次来看看他们的使用方法。

#!/bin/sha=4b=2c1=$((${a}+${b}))c2=$((${a}-${b}))c3=$((${a}*${b}))c4=$((${a}/${b}))c5=$((${a}%${b}))echo "a + b=" ${c1}echo "a - b=" ${c2}echo "a * b=" ${c3}echo "a / b=" ${c4}echo "a % b=" ${c5}

表达式方式1

#!/bin/sha=4b=2c1=$[${a}+${b}]c2=$[${a}-${b}]c3=$[${a}*${b}]c4=$[${a}/${b}]c5=$[${a}%${b}]echo "a + b=" ${c1}echo "a - b=" ${c2}echo "a * b=" ${c3}echo "a / b=" ${c4}echo "a % b=" ${c5}

表达式方式2

除了这些运算之外,shell也支持自增和自减运算,这里以let命令为例:

#!/bin/shc1=2c2=2c3=2let c1++let c2--let c3+=1echo "c1=" ${c1}echo "c2=" ${c2}echo "c3=" ${c3}

自增和自减

上面的这些运算方法都有各自的要求,在使用的时候我们一定要清楚它们的使用方法。另外,在默认情况下shell是不支持小数运算,大家可以发现上面的运算都是整数运算,怎么进行小数运算呢?

我们可以借助Linux平台下的bc计算器进行小数运算。

#!/bin/sha=1.411b=1.332c1=`echo "$a+$b"|bc`c2=`echo "$a-$b"|bc`c3=`echo "$a*$b"|bc`c4=`echo "scale=3;$a/$b"|bc` #scale用来指定小数的位数echo $c1echo $c2echo $c3echo $c4

小数运算

数组

Shell可以定义数组用来存放多个数据,格式如下,数组中的各个元素需要使用空格隔开,数组在定义时可以不用指定数组的大小。

array=(value1 value2 value3 ...)

在访问数组时,可以使用中括号和下标([下标])访问各个元素,它的下标也是从0开始的。

#!/bin/sha=(hello world code)echo ${a[0]}echo ${a[1]}echo ${a[2]}

数组访问

除了用下标访问单个元素之外,是否有其他方法获取所有元素呢?我们可以使用*和@符号获取数组的所有元素。这两个符号是不是很熟悉?我们在字符串变量操作章节用到过这两个符号。

#!/bin/sha=(hello world code)echo ${a[*]}echo ${a[@]}

获取数组所有元素

同样的,与获取字符变量长度类似,我们也可以使用#符号来获取数组的长度。

#!/bin/sha=(hello world code)echo ${#a[*]}

获取数组长度

关系运算

关系运算也就是比较运算,因为在shell里都是字符串类型,我们怎么比较数字的大小呢?shell中专门提供了一些专门用来关系运算的运算符。如下:

-eq:可以判断两个数是否相等,相等则为ture,格式为[ $a -eq $b ];-ne:可以判断两个数是否不相等,不相等则为true,格式为[ $a -ne $b ];-gt:可以左边的数是否大于右边的,如果是则为true,格式为[ $a -gt $b ];-lt:可以判断左边的数是否小于右边的,如果是则为true,格式为[ $a -lt $b ];-ge:可以判断左边的数是否大于等于右边的,如果是则为true,格式为[ $a -ge $b ];-le:可以判断左边的数是否小于等于右边的,如果是则为true,格式为[ $a -le $b ]。

这里要注意变量和中括号两边是有空格隔开,运算符和变量之间也有空格隔开,具体我们可以通过一个例子来进一步了解它们的使用。

#!/bin/sha=1b=2if [ $a -eq $b ];then echo "yes"else echo "no"fiif [ $a -ne $b ];then echo "yes"else echo "no"fiif [ $a -gt $b ];then echo "yes"else echo "no"fiif [ $a -lt $b ];then echo "yes"else echo "no"fi

这里用到了判断语句if...else,详细内容可以在条件语句章节再深入了解。

关系运算

上面的是数值关系运算,当然,对于字符串同样也有类似的元素符。

=:判断两个字符串是否相等,相等则为真,[ $a=$b ] ;!=判断两个字符串是否不相等,不相则为真,[ $a !=$b ];-z 判断字符串长度是否为0,如果是则为真,[ -z $a ];-n 判断字符串长度是否不为0,如果是则为真,[ -n "$a" ];$ 判断字符串是否为空,如果不为空则为真,[ $a ];
#!/bin/sha="hello"b="hello"c="world"d=""echo "a=b ?"if [ $a=$b ];then echo "yes"else echo "no"fiecho "a !=b ?"if [ $a !=$b ];then echo "yes"else echo "no"fiecho "a !=c ?"if [ $a !=$c ];then echo "yes"else echo "no"fiecho "len(c)=0 ?"if [ -z $c ];then echo "yes"else echo "no"fiecho "len(d) !=0 ?"if [ -n "$d" ];then echo "yes"else echo "no"fiecho "len(a)=0 ?"if [ $a ];then echo "yes"else echo "no"fi

字符串

逻辑运算

除了我们上面介绍的算术运算和关系运算,Shell还有逻辑运算。逻辑运算主要有逻辑与和逻辑或运算。

逻辑与运算使用&&表示,运算符两边都为真则结果为真;逻辑或运算使用||表示,运算符两边只要有一个为真则结果为真。

我们通过一个例子来对逻辑运算进一步了解。

#!/bin/sha=1b=2c=1echo "a=c && a !=b ?"if [[ $a -eq $c && $a -ne $b ]];then echo "yes"else echo "no"fiecho "a=b || a=c ?"if [[ $a -eq $b || $a -eq $c ]];then echo "yes"else echo "no"fi

逻辑运算

条件语句

与其他语言一样,shell脚本编程也可以进行流程控制,比如,条件语句,循环语句等,这一章节我们学习条件语句。

条件语句中主要通过if else then elif fi等关键字组成,主要可以组成下面几种情况:

单分支双分支多分支:多个条件,多个执行分支

单分支这种情况,结构比较简单,一个条件一个执行分支。

a=1if [ $a==1 ];then    echo "a=1"fi

单分支

双分支的情况,比单分支多一个执行分治。

a=1if [ $a==2 ];then    echo "a=1"else echo "a !=1"fi

双分支

多分支结构比较适合多种条件,多个执行分支的情况。

a=2if [ $a==1 ];then    echo "a=1"elif [ $a==2 ];then echo "a=2"else echo $afi

多分支

对于if的分支语句大家要注意格式问题,在[]里的条件表达式一定要和两边中括号符号用空格隔开。

此外,还有一种多分支语句case语句,格式为:

case $变量 in    "value1")        执行语句1        ;;    "value2")        执行语句2        ;;    *)        执行其他语句        ;;esac

我们看一个case语句的示例:

#!/bin/shread -p "please in put a number:" numcase $num in"1") echo "Start 1th flow" ;;"2") echo "Start 2th flow" ;;*) echo "Do nothing"esac

case语句

上面的这些只是一些简单的语句结构,大家只要掌握了这几种分支语句的用法,就可以组成更加复杂的分支语句,比如,多个判断条件,多个分支嵌套等。

循环语句

用于流程控制的另一种方式是循环语句,Shell中常见有for while until select这四种循环语句。下面我们依次来了解这四种循环方式。

for循环for(())和for...in这两种形式,我们可以根据自己的需要进行选择。

先来看看for(())这种循环格式:

for((ex1;exp2;exp3))do  循环体done

这里我们可以结合的数组的知识来举个循环的栗子。

a=("hello" "world" "hello" "shell")for((i=0;i<4;i++))do  echo ${a[i]}done

for循环

我们通过定义一个递增变量i,依次访问数组各个元素。有没有更简单的变量方法呢?我们再看下面一个例子。

a=("hello" "world" "hello" "shell")for v in ${a[*]}do  echo $vdone

for...in

上面的例子用的是第二种for...in的循环格式,其格式如下,它可以方便的遍历一个列表或数组,而不需再定义递增/递减变量。

for var in listdo  循环体done

接下来我们看while循环,while循环的格式如下,

while [ 条件表达式 ]do  循环体done

再看一个例子:

a=("hello" "world" "hello" "shell")i=0while [ $i -lt 4 ]do  echo ${a[i]} let i++done

while

while循环需要注意条件表达的写法,相信看了上面的关于条件语句的同学已经很清楚了。

在shell中有一个与while循环恰好相反的循环until循环;在while循环中条件表达式成立就会进入循环体,而在until循环中条件表达式不成立才会进入循环,until循环的格式如下:

until [ 条件表达式 ]do  循环体done

我们将上面while循环例子的条件表达式稍加改动。

a=("hello" "world" "hello" "shell")i=0until [ $i -ge 4 ]do  echo ${a[i]} let i++done

until

对于until循环语句来说,一般没有上面的几种循环语句较为常用。

最后,还有一种较为特殊的循环select,我们先看一下它的格式:

select var in listdo    statementsdone

为什么说它是一种特殊的循环?我们看下面这个例子:

a=("hello" "world" "hello" "shell")i=0select v in ${a[*]}do  echo $vdone

select

从这里例子上,我们可以发现在每行打印前面都有一个序号,我们还可以选择其中一个序号,会输出对应需要的结果。它是shell中特有的一种结构,通常和case...in语句一起使用,通过根据选择的序号不同,可以选择执行case...in里不同的动作。

a=("公司A" "公司B" "公司C" "公司D")select v in ${a[*]}do case $v in   "公司A")   echo "恭喜您,你选择了公司A !"   break   ;;  "公司B")   echo "恭喜您,你选择了公司B !"   break   ;;  "公司C")   echo "恭喜您,你选择了公司C !"   break   ;;  "公司D")   echo "恭喜您,你选择了公司D !"   break   ;;  *)   echo "您没有选择任何一个公司,请重新选择!"  esacdone

select in 和 case in

函数

在一个复杂的功能的脚本程序中,会有很多重复或相似的功能,为了避免大量的重复代码,这个时候函数的作用体现出来了。一般的我们会将一些相似的或重复的操作抽象成一个函数,并根据参数的不同返回相应的结果。这样程序将更具模块化,逻辑也更加清楚,便于开发和维护。

当然,在shell中也可以使用函数。其格式如下:

function name() {    # 函数体    return value}

这里function是用来定义函数的关键字,name是需要我们自定义的函数名,return value是函数的返回值。现在我们来定义一个函数:

function test1() { echo "this is a function"  return 0}

该怎么调用函数呢?直接写函数名即可,我们看一个完整版程序:

function test1() { echo "this is a function"  return 0}test1 #调用函数

函数1

上面函数没有带参数的,那如果有参数怎么办呢?我们继续看例子:

function test2() { echo "parameter1 : $1" echo "parameter2 : $2"  return 3}test2 1 2 #调用函数echo $? #获取函数返回值

函数2

实际上,函数中是不要定义形参的,在调用时在函数后面加上实参就可以了。而函数体中可以通过$加参数编号访问参数,比如,第一个参数$1,到第十个参数以上就需要加上{}符号,比如${10},而函数返回值需要在调用该函数后通过$?获得。

文件包含

有的时候某个功能可能被多个脚本使用,这时就需要在将这个功能放到一个公共的文件中,需要这个功能的脚本直接包含这个公共的文件即可,这就是文件的包含,同样的Shell也是支持文件包含的。

在Shell中可以使用.或source加上文件名来包含文件。直接来看例子:

先建一个文件test_one.sh:

#test_one.shvar1=1

再建一个文件test_two.sh:

#test_two.shvar2=2

下面我们在建一个文件包含test_one.sh和test_two.sh这两个文件。

. ./test_one.shsource ./test_two.shecho "file one var1=${var1}"echo "file two var2=${var2}"

文件包含

这里需要注意.和./test_one.sh文件之间是有一个空格。

最后

至此,我们已经学会了shell编程的一些基本知识。文中使用的都是一些简单的例子,在实际的shell脚本中往往都是比较复杂的逻辑。不过,再复杂的代码也是有这些简单的结构组成。因此,大家一定要有一个扎实基础和掌握一个完整的shell知识体系。

发表评论