shell十三问总结

我们知道计算机的硬件资源比如磁盘,IO,内存都是由软件来统一管理的,这类特殊的软件就是常说的操作系统,windows在底层的资源控制基础上构建了自己的界面,非常适合使用,只需要到处点点就能完成我们需要的功能。这是一种控制资源的方式,同时也可以使用command的方式来操作底层的资源。liunx中最重要的部分是它的内核,内核管理着系统的资源,同时也提供给我们操作内核的接口,就是我们经常用到的shell(壳),主流的shell有以下几种:

sh:

burne shell (sh)

burne again shell (bash)

csh:

c shell (csh)

tc shell (tcsh)

korn shell (ksh)

接触比较多的是bash和ksh,几种不同的shell功能大体相似,当然也各有特点。

一般给非管理员用户显示的是$,管理员显示的是root。linux下的换行符(按下enter键)用CR表示,当遇到CR时,shell解释器会去解释CR前面的command line,解释命令行是先按照IFS去分割命令行,然后对其中的元字符进行处理,比如:echo $A 其中A的值为hello,按照IFS(默认为tab,newline,space)拆解为echo和$A然后对元字符$进行解释,取A变量的值,最后输出hello到屏幕。

一、echo

echo命令是我们经常需要用到的输出命令,可以查看参数的值,其中提供了几个参数,能够实现不同的效果,比如echo -n就是取消末尾的换行符,可以在环境上试试输出echo -n "a" 和echo "a"有什么不同。如果我们想在默认再增加一个换行可能会想到echo "a\n",这是行不通的,echo默认执行的是-E参数,表示不去解释反斜线的字符转换,因此需要开启\功能,需要使用-e参数,如下:echo -e "a\n"。

二、双引号""和单引号‘‘

在shell中双引号和单引号的作用是不同的,shell中的字符可以分为两种,一种是普通字符,一种是元字符,比如$是一种元字符,当执行到元字符的时候shell会去做相应的动作,比如echo $A就是打印变量A的值,但是如果我们想打印“$A”那么应该怎么实现呢,答案就是使用单引号,echo ‘$A‘,单引号中的所有元字符都会被当做普通的字符来处理,那么双引号又有什么不同呢,双引号会关闭大部分的元字符处理,但是有少部分还是会当做元字符来解释,比如$符号,另外还有一种关闭元字符的做法是在元字符前加/反斜线。

三、var=value和export

严格来说在当前shell中定义的的变量均为本地变量,只有export后才会成为环境变量,供后面的命令使用,export命令的详细解释以后会提到。

四、exec和source

执行shell的时候经常用到source *.sh,实际上我们执行*.sh脚本的时候,会产生一个subshell进程来执行,并且该子进程的环境变量和父进程的环境变量不是共享的,因此假如我们定义cd /home/a/b/d命令在test.sh脚本中,并且在/home/a下面执行test.sh,实际上目录并不会切换到/home/a/b/d下,就是这个原因。那么如何才能执行test.sh使得目录切换,shell提供了两种方式来阻止产生subshell进程执行脚本,source和exec,这两个命令会在当前的shell进程中完成脚本的调用。那么这两种方式的调用又有什么区别呢?看下面的一个例子:

1.sh

#!/bin/bash
A=B
echo "PID of 1.sh before exec/source/fork:$$"
export A
echo "1.sh :\$A is $A"
case $1 in
        exec)
                echo "using exec..."
                exec ./2.sh ;;
        source)
                echo "using source"
                . ./2.sh ;;
        *)
                echo "using fork"
                ./2.sh ;;
esac
echo "PID of 1.sh after exec/source/fork:$$"
echo "1.sh:\$A is $A"

2.sh

#!/bin/bash
echo "PID for 2.sh is: $$"
echo "2.sh get \$A=$A form 1.sh"
A=C
export A
echo "2.sh:\$A is $A"

执行./1.sh fork后的结果:

PID of 1.sh before exec/source/fork:18885

1.sh :$A is B

using fork

PID for 2.sh is: 18886

2.sh get $A=B form 1.sh

2.sh:$A is C

PID of 1.sh after exec/source/fork:18885

1.sh:$A is B

执行./1.sh exec后的结果:

PID of 1.sh before exec/source/fork:20952

1.sh :$A is B

using exec...

PID for 2.sh is: 20952

2.sh get $A=B form 1.sh

2.sh:$A is C

执行./1.sh source后的结果:a

PID of 1.sh before exec/source/fork:26519

1.sh :$A is B

using source

PID for 2.sh is: 26519

2.sh get $A=B form 1.sh

2.sh:$A is C

PID of 1.sh after exec/source/fork:26519

1.sh:$A is C

下面逐一分析打印的结果:

默认的fork执行,会产生一个子进程来执行shell脚本,其中父进程中的export效果会传递到子进程,但是子进程中的export效果并不会传递给父进程,因此export命令的效果是单向的,从父进程传递子进程。

exec和source执行并不会产生子进程,而是在当前进程执行脚本,不同点是exec会终止当前的脚本执行,当子脚本执行完毕后,整个执行过程就算完毕了。

五、()和{}的区别

这里要引入一个命令组的概念,就像是其他语言中的函数,()和{}的不同是()是在子shell中执行,{}是在本shell中执行,说到这里不得不提出一个概念,函数,在shell中定义函数的方式有两种,一种是function_name{},还有一种是function_name (){}。

六、$(())、${}和$()的区别

在bash中,$()和``都是用作命令替换,命令替换和之前的变量替换的概念有些类似,比如dir=$(pwd),首先pwd的执行结果会赋值给变量dir,${}的作用是变量替换,比如A=B;echo ${A},实际上在这里也可以直接echo $A,但是假如写成echo $AA,则shell是不识别的,因此${}起到一个边界的作用,但是如果你只认为${}只是起到边界的作用,那就太小瞧它了。

假设有变量file=/dir1/dir2/dir3/my.file.txt

我们可以用${}进行不同的变量替换得到不同的值。

${file#*/}:去掉第一个/及其左边的所有字符,结果为dir1/dir2/dir3/my.file.txt

${file##*/}去掉最后一个/及其左边的所有字符,结果为my.file.txt

${file%/*}去掉最后一个/及其右边的所有字符,结果为/dir1/dir2/dir3

${file%%/*}:拿掉第一个 / 及其右边的字串:(空值)

#是去掉左边,%是去掉右边,一个是最短匹配,两个是最长匹配

${file:0:5} 结果为从第0个开始向右取5个字符/dir1

因此${file:offset:length}从offset开始向右取length个字符

${file/dir/path}将第一个dir替换为path,结果为/path1/dir2/dir3/my.file.txt

${file//dir/path}将所有的dir都替换为path。

上面的是字符的替换,还可以根据当前的值是否为空来做替换,如下:

${file-myfile.txt}如果file未定义则输出myfile.txt

${file:-myfile.txt}如果file未定义或者为定义为空则输出myfile.txt

${file+myfile.txt}如果file有定义则不论是否为空,都输出myfile.txt

${file:+myfile.txt}如果file不为空,则输出myfile.txt

${file=myfile.txt}如果file未定义则输出myfille.txt同时赋值file为myfile.txt

${file:=myfile.txt}如果file未定义或者为空,则输出myfile.txt

${#file}输出file变量的长度

顺便再来介绍一下bash中的数组array

数组的定义类似:A=(a b c d e)中间用空格分割

如果要得到这个数组的内容,可以使用${A[@]}或者${A[*]}

最后再来看下$(())的用途,$(())方便我们做整数运算,比如a=1;b=2;echo $((a+b))输出为3。$(())为我们做比较和运算提供了类C语言的风格。

七、[email protected]和$*的差别

比如我们有个sh脚本名称为test.sh,它可以接受参数,如下 test.sh a b c,获得外部参数的方式为$1 $2 $3分别获取a b c,如果要获取脚本身的名称则使用$0。注意脚本中定义的函数也可以接收参数同样可以使用$1...这种方式获取传入的参数。不同的时$0不是函数的名称而是最外面脚本的名称。

$10表示的并不是获取第十个参数,而是获取第一个参数后面再加上字符串0,因此如果要获取第十个参数可以使用${10},或者使用shift命令,shift 1为取消第一个参数($0)排除,shift 5为取消前5个参数。

再介绍一个参数$#表示获取传入的参数总数,比如test.sh one two three 则$#为3。

如果要获取所有的参数则可以使用[email protected],比如test.sh one two three则获取到三个word,而$*是将参数当做一个整体。

八、&&和||的差别

在介绍$$和||之前先来了解一个新的概念,return value,在执行command或者function的时候都会传值会父进程,我们可以使用$?来获取这个最新的返回值,return value只有两种状态,0的话为真,非0的话为假,比如:

假设myfile.txt存在,而a.txt不存在,ls a.txt后再echo $?为非0,如果ls myfile.txt则为0。可以使用test expersion或者[ expersion ]来测试返回值。不过我更习惯使用[]这种语法。

接下来就可以看看$$和||的差别了,command1 && command2表示如果command1命令返回真则执行command2。command1 || command2表示,如果command1返回假则执行command2。

九、<和>

大概存在三种FD(文件描述符),分别为0标准输入,1标准输出,2错误输出,>表示标准输出重定向与1>相同。

2>&1表示把标准错误输出重定向到标准输出。

&>file表示把标准输出和标准错误输出重定向到文件file中。

2>&-表示将标准错误输出关闭

>/dev/null 2>&1表示将标准错误输出绑定到标准输入并且标准输入重定向到/dev/null,也即什么都不会输出

十、case和if

有时候需要根据当前的值来执行不同的逻辑,if在这里就派上了用场,标准的if用法为:

if comd1;then

comd2

elif comd3;then

comd4

else

comd5

fi

如果then后面不想跑任何命令可以使用:这个null command来替代。

如果条件比较多并且为字符串则可以使用另外一种语法,case

case "$1" in

start)

start

;;

stop)

stop

;;

restart|reload)

restart

;;

*)

exit 1

esac

十一、for、while与until

loop是非常基本的一种逻辑控制,所有的语言都提供了自己的循环控制语句

for loop从一个清单列表中读取值,依次做处理:

for var in one two three four five

do

...

done

下面给出一个累计变量的语句:

for ((i=1;i<=10;i++))

do

...

done

如果改为while实现则如下:

num=1

while [ $num -le 10 ];do

...

done

-le表示小于等于

while是在条件为true时进入循环,until则相反,是在条件为false时进入循环。

同样循环中也有break和continue关键字,和java等其他语言的用法是一样的,就不做解释了。

上面就是shell十三问的大体内容,有些内容并没有涉及到,后续会对一些比较常用的命令比如grep,sed,awk等进行简单的讲解。

时间: 2024-10-21 21:01:14

shell十三问总结的相关文章

&lt;转&gt;shell经典,shell十三问

shell 十三问: 1) 为何叫做 shell ? 2) shell prompt(PS1) 与 Carriage Return(CR) 的关系? 3) 别人 echo.你也 echo ,是问 echo 知多少? 4) " "(双引号) 与 ' '(单引号)差在哪? 5) var=value?export 前后差在哪? 6) exec 跟 source 差在哪? 7) ( ) 与 { } 差在哪? 8) $(( )) 与 $( ) 还有${ } 差在哪? 9) [email prot

shell十三问(转)

这个我记得是在chinaunix论坛上最早出现的帖子. Shell 十三问 作者:www.chinaunix.net之網中人 1) 为何叫做 shell ? 在介绍 shell 是甚么东西之前,不妨让我们重新检视使用者与计算机系统的关系: 我们知道计算机的运作不能离开硬件,但使用者却无法直接对硬件作驱动, 硬件的驱动只能透过一个称为"操作系统(Operating System)"的软件来控管, 事实上,我们每天所谈的 linux ,严格来说只是一个操作系统,我们称之为"核心(

Shell 十三问 的学习记录

在 BBS上看到了Shell十三问的帖子,由于比较就远了,怕以后再也找不到了,就把笔记贴过来了, 原帖地址: shell 十三问http://bbs.chinaunix.net/thread-2033675-1-1.html 贴出我做的笔记: <一>.为何叫做shell 使用者通过shell(操作系统即核心kernel的外壳)与kernel沟通,这是shell与kernel的命名的关系. 从技术角度讲,shell的最简单定义是——命令解译器( Command Interpreter ) /et

Shell 十三问[转]

shell 十三问:1) 为何叫做 shell ? 2) shell prompt(PS1) 与 Carriage Return(CR) 的关系? 3) 别人 echo.你也 echo ,是问 echo 知多少? 4) " "(双引号) 与 ' '(单引号)差在哪?  5) var=value?export 前后差在哪?6) exec 跟 source 差在哪? 7) ( ) 与 { } 差在哪?8) $(( )) 与 $( ) 还有${ } 差在哪? 9) [email protec

linux shell 快速入门小例子(shell十三问学习NOTE)

读CU论坛shell十三问后进行的几次小实验,备忘一下! SHELL十三问地址:http://bbs.chinaunix.net/thread-218853-1-1.html #!/bin/bash function func_com() { local a=1 local b="2c3" echo ${a}b echo $ab } function func_array() { echo "##### func_array #####" local PATH=&q

别人 echo 、你也 echo ,是问 echo 知多少?-- Shell十三问&lt;第三问&gt;

别人 echo .你也 echo ,是问 echo 知多少?-- Shell十三问 承接上一章所介绍的 command line ,这里我们用 echo 这个命令加以进一步说明. 温习---标准的 command line 包含三个部件: command_name option argument echo 是一个非常简单.直接的 Linux 命令:将 argument 送出至标准输出(STDOUT),通常就是在监视器(monitor)上输出. 为了更好理解,不如先让我们先跑一下 echo 命令好

Shell十三问更新总结版 -- 什么叫做 Shell?-- Shell十三问&lt;第一问&gt;

Shell十三问更新总结版 简介 ChinaUnix 论坛 Shell 版名为網中人的前辈于 2004 年发布的精华贴,最近回炉这块内容,觉得很多东西讲的实在透彻,非常感谢前辈網中人,同时我个人也对这个系列做了一些总结和备注,写于下面章节,虽然这篇文件写于2004年,但是Shell这个东西变化很少,这个系列希望能够帮助到大家提供给大家,有心学习的同学不要读一遍练习一遍就算完了,第一遍和第二遍和第十遍读这个系列,感受绝对不一样,疏漏处请见谅. 網中人原贴:http://bbs.chinaunix.

var=value?export前后差在哪?-- Shell十三问&lt;第五问&gt;

var=value?export前后差在哪?-- Shell十三问 这次让我们暂时丢开 command line ,先来了解一下 bash 变量(variable)吧.所谓的 变量,就是就是利用一个特定的"名称"(name)来存取一段可以变化的"值"(value). 在 bash 中,你可以用 "=" 来设定或重新定义变量的内容: name=value 在设定变量的时侯,得遵守如下 规则: 等号左右两边不能使用区隔符号(IFS),也应避免使用 s

exec 跟 source 差在哪?-- Shell十三问&lt;第六问&gt;

exec 跟 source 差在哪?-- Shell十三问 这次先让我们从 CU Shell 版的一个实例贴子来谈起吧: 例中的提问是: cd /etc/aa/bb/cc 可以执行 但是把这条命令写入 shell 时 shell 不执行!这是什么原因呀! 我当时如何回答暂时别去深究,先让我们了解一下进程(process)的观念好了.首先,我们所执行的任何程序,都是由父进程(parent process)所产生出来的一个子进程(child process),子进程在结束后,将返回到父进程去.此一现