Shell学习笔记

嘛,作为习惯使用Mac作为开发系统的开发者,Shell算是必须学习的内容之一。CI的脚本之类的也需要用Shell来写,总之学习一下没有坏处。本文主要以基础的Bourne Shell为学习对象,记录学习过程中的一些知识要点,和其他笔记一样,基本上是写给自己看的,不喜欢的不要拍砖。

1.关于 #!

'#'表示注释,而'#!'则告诉系统当前文件应该用什么来执行。
例如:

#!/bin/sh
echo Hello World

/bin/sh是Bourne shell在Unix下的标准路径,如果是Linux下,它则是一个指向bash(最新版是dash)的软连接。

2.关于chmod

对用户创建的文件来说,默认只有读写权限,没有执行权限。为了让脚本可以被执行,就需要通过chmod命令修改权限。

r 表示读权限 用数字表示为4
w 表示写权限 用数字表示为2
x 表示执行权限 用数字表示为1
- 表示无权限 用数字表示为0

chmod 777 test.sh

3.变量赋值

变量在赋值的时候没有空格,否则系统会以为这是一条执行命令语句,例如:

#!/bin/sh
MY_MESSAGE="Hello World"
echo $MY_MESSAGE

如果=左右有空格的话,系统还以为MY_MESSAGE是一个命令,而=和“Hello world”是命令的两个参数。
如果变量没有被赋值,那么变量将被视为一个空字符串。

4.使用read命令

read命令可以从标准输入中读取一行并将其赋值给你提供的变量。

#!/bin/sh
echo "What is your name?"
read MY_NAME
echo "Your name is $MY_NAME"

注意到read命令能够自动给你的输入加一对双引号,这意味着你可以安全的使用空格。

What is your name?
Grand Kindom
Your name is Grand Kindom

5.变量的作用域

一般来说,变量的作用域只限于当前的shell环境,也就是#!bin/sh之下的环境中。
例如,我们有如下的shell脚本:

#!/bin/sh
echo "MY_VAR is $MY_VAR"
MY_VAR="Hello"
echo "MY_VAR is $MY_VAR"

现在我们执行脚本:

$ MY_VAR=hello
$ ./test.sh
MY_VAR is
MY_VAR is Hello

可以发现,我们在交互式shell(interactive shell)下赋值的变量,对新生成的用来运行脚本的子shell环境没有任何影响。
为了能让子shell可以使用我们的变量,需要使用export命令允许子shell继承变量。

$ MY_VAR=World
$ export MY_VAR
$ ./test.sh
MY_VAR is World
MY_VAR is Hello

脚本中的第三行,我们更改了MY_VAR变量的值,我们尝试在交互式shell下输出:

$ echo $MY_VAR
World

发现值并没有发生任何变化,也就是说子shell对父shell的变量没有影响。
为了做到这点,我们需要将脚本在当前的交互式shell中运行,而不是新生成一个shell来运行。这一过程叫做source。通过.命令,我们可以source一个脚本:

$ . ./test.sh
MY_VAR is World
MY_VAR is Hello
$ echo $MY_VAR
Hello

MY_VAR变量被成功改变了!这也是.profile.bashrc的工作原理。

6.变量的边界

考虑以下脚本

#!/bin/sh
echo "Please tell your name"
read MY_NAME
echo "Hello $MY_NAME"
echo "Now I will create a file called $MY_NAME_file"
touch "$MY_NAME_file"

文件能够创建成功吗?不行。因为shell不知道变量的起始位置,它还以为有一个变量的名字叫做'MY_NAME_file',而事实上并没有这样的一个变量,因此文件创建失败了。
使用花括号可以界定变量的边界,他告诉shell:花括号内的是一个变量,需要单独对待。

echo "Please tell your name"
read MY_NAME
echo "Hello $MY_NAME"
echo "Now I will create a file called ${MY_NAME}_file"
touch "${MY_NAME}_file"

再次运行上述修改后的脚本,我们会发现文件被成功创建。

为什么touch命令的参数要用双引号圈起来呢?这是为了防止你输入的名字有空格。比如说你输入的名字是Grand Kindom,那么最后的touch命令就会变成touch Grand Kingdom_file。结果会生成两个文件,一个叫做Grand,另一个叫做Kindom_file

7.循环

1)for循环

for i in hello 1 * 2 world
do
  echo "i is set to $i in the loop now"
done

2)while循环

INPUT_STRING=hello
while [ "$INPUT_STRING" != "bye" ]
do
  echo "Please type something in (bye to quit)"
  read INPUT_STRING
  echo "You typed: $INPUT_STRING"
done

当while后跟着一个:时,条件表达式永远为true,这在某些情况下很有用。

while :
do
  echo "Please type something int (^C to quit)"
  read INPUT_STRING
  echo "You typed: $INPUT_STRING"
done

另一个比较常见的使用方式是while read f循环

while read f
  do
    case $f in
      hello)        echo English    ;;
        howdy)      echo American   ;;
        gday)       echo Australian ;;
        bonjour)    echo French ;;
        "guten tag")    echo German ;;
        *)      echo Unknown Language: $f
        ;;
    esac
  done < myfile

8.测试

在shell中,[代表测试,它本身是一个程序,就像lschmod一样,而不是一个符号。所以[后面必须跟空格,否则shell会把[和后面的字符拼在一起解释,导致问题。在Unix系统中,[是一个指向test程序的软连接,也就是说:

if [$foo = "bar" ]

会被解释为if test$foo = "bar" ],这也就是问题的所在了。可以看到,在shell中,使用=比较字符串,而对于整数则使用-eq

1) if

if [ ... ]
then
  ...
else
  ...
fi

注意then必须另起一行。也可以加上;使其和if在同一行。在shell中;表示后面的语句是另一行语句,不过出于某种目的(比如说节约空间)所以写在同一行。与其对应的符号是\,表示下一行的语句应该和本行语句视为同一行。下面的第二个shell运用了逻辑运算符的短路性质。

if [ ... ]; then
  ...
fi
[ "$X" -nt "/etc/passwd" ] && \
      echo "X is a file which is newer than /etc/passwd"

也可以使用elif

if  [ something ]; then
 echo "Something"
 elif [ something_else ]; then
   echo "Something else"
 else
   echo "None of the above"
fi

9.预设变量

1) $0 $1 ... $9$#

  • $0表示当前程序(脚本)的名称
  • $1 .. $9表示调用脚本时候传入的前9个参数
  • 变量$@表示所有参数 $*也有类似的作用但是它不保留空格和引号(通常情况下避免使用$*)
  • $#表示脚本调用时候传入的参数个数
#!/bin/sh
echo "I was called with $# parameters"
echo "My name is $0"
echo "My first parameter is $1"
echo "My second parameter is $2"
echo "All parameters are $@"
$ ./var3.sh hello world earth
I was called with 3 parameters
My name is ./var3.sh
My first parameter is hello
My second parameter is world
All parameters are hello world earth

2) $?

这个变量包含上一个命令的退出值。在shell中,返回值0表示正常退出,所以可以通过test来判断上一个命令执行的时候有没有执行成功,增加程序的鲁棒性。

#!/bin/sh
/usr/local/bin/my-command
if [ "$?" -ne "0" ]; then
  echo "Sorry, we had a problem there!"
fi

3)$$$!

  • $$变量表示当前的进程标识符,如果你的脚本允许存在多个实例同时运行的话,在创建文件的时候就可以在文件名上带上这个进程标识符避免冲突:/temp/my_file.$$
  • $!变量表示最后运行的后台进程标识符

10.花括号的高级用法

花括号除了用来保证变量的边界外,还可以用来处理字符串undefined或者为null的情况(这两者在shell里基本没有区别),为其添加一个默认值,方法是在变量名后面加上:-

#!/bin/sh
echo "What is your name [ `whoami` ] \c"
read MY_NAME
echo "Hello ${MY_NAME:-`whoami`}"

上述脚本中的\c告诉echo命令不要换行。反引号中的内容whoami被视为一个命令,命令在执行之后的标准输出会被替换为反引号所在的内容。而whoami命令输出的是当前登录的用户名称,所以上述命令的作用是让用户键入自己的名称,并且会显示当前登录的用户名称作为默认值,如果用户直接点了回车没有输入内容的话,则会输出用户的登录名。

$ ./test.sh
What is your name [ melot ] abc
Hello abc
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,646评论 4 366
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,979评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,391评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,356评论 0 215
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,740评论 3 293
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,836评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,022评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,764评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,487评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,728评论 2 252
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,200评论 1 263
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,548评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,217评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,134评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,921评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,919评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,766评论 2 274

推荐阅读更多精彩内容