恩,这是由奇技淫巧组成的语言,没有之一。奇技淫巧到,他的语法出如今你无数个灵光一现时刻~python
我:蒋哥你shell好厉害!mysql
蒋哥:恩git
我:要多久啊sql
蒋哥:(基于Java,python,js等)要一段时间docker
shell,壳,计算机命令终端,每一个unix体系的机器最原始都是使用这个与计算机操做系统进行交互的,相似的,windows操做系统下满就是bat(批处理文件)。每次Linux系统启动,登录以后,都会默认启动几个这种命令终端,若是图形界面有的话,通常会默认进入图形界面。图形界面之上,咱们也可使用Terminal这种模拟的命令终端,进行命令操做,这东西相似于windows的cmd。shell
对于编程这么多年,变量很好理解,无非就是一个瞎几把命名的一个单词,赋值一个value嘛~真的吗?奇技淫巧来了,请看下面数据库
# ① var1=123 # ② var2='jicheng${var1}' # ③ var3="jicheng${var1}" # ④ var4=`pwd` # ⑤ var4 = `pwd` # ⑥ var4=$(pwd)
①shell变量没类型,弱类型,万物皆字符串,即便是这个,也是var1值是"123"express
②③单双引号不同,单引号内部不转义,写啥是啥;双引号会转义,会替换变量值编程
④这种上引号是执行引用起来的字符串,因此被引用的要能被执行,结果赋值给等号左面的变量ubuntu
⑤这种是错误语法。赋值操做的等号两边不能有任何空格,这种有空格的,后面会将
⑥和④同样
完了?远远还没,来点晋级的:
# ① var4=${var1:-value} var4=${var1-value} # ② var5=${var1:=value} var5=${var1=value} # ③ var6=${var1:?value} var6=${var1?value} # ④ var7=${var1:+value} var7=${var1+value}
解说:不带冒号表明var1是否为未赋值,带了表明var1是否为未赋值或是空值
①var1未赋值(或空值)将"value"赋值给var4变量
②var1未赋值(或空值)将"value"赋值给var4,且一样赋值给var1
③var1未赋值(或空值)将"value"做为标准错误输出,用于进行变量判空用的
④var1未赋值(或空值),什么都不作,不然value代替var1的值,赋值给var7,var1的值不变
一个真正的shell脚本在执行过程当中,会有一些特殊的变量,这个对理解shell程序相当重要,来战:
#!/bin/bash # shell_test.sh脚本 echo $0 echo $(basename $0) echo $1 $2 echo $# echo $* echo "$*" echo $@ echo "$@"
$0:
获取执行脚本本身的文件名,执行的输入全字符串,例如./shell.sh、/etc/profile_test.sh,若是想单纯获取名字,要用:$(basename $0)
$1,$2,$3……..$n这种
回去执行名称后面对应的输入参数,$1表明第一个,$n表明第n个
$#
获取输入参数一共有多少个
$*与$@
不加引号,两个同样:都是将入参使用IFS定义的分隔符进行拆分;加了就有区别:$*会把全部入参当作一个总体的字符串,而$@会将使用双引号的入参当作一个,不进行IFS分隔符拆分操做。下面代码是两个变量的对比试验:
#!/bin/bash # 对$*与$@作对比试验 # 将带引号的入参进行IFS分割拆分 for i in $*; do echo $i done # 恩,这就是一个大的字符串 for i in "$*"; do echo $i done # 将带引号的入参进行IFS分割拆分 for i in $@; do echo $i done # 不将带引号的入参进行IFS分割拆分 for i in "$@"; do echo $i done
每次运行shell脚本,或者咱们开启一个Terminal,或者咱们远程登录一个命令终端,其实都是有预先设置好的变量存在的,这个就叫:环境变量。若是是全局的环境变量,就是说,每一个用户登陆都能看到的,能够说是全局变量,相似于windows里面的系统变量的概念;若是环境变量只是当前用户可以看到的,那就是局部环境变量,相似于windows里面的环境变量的概念。内部有几个很关键的脚本文件,专门用来设置全局与局部变量的,大体总结下:
下面是profile的源代码:
# /etc/profile: system-wide .profile file for the Bourne shell (sh(1)) # and Bourne compatible shells (bash(1), ksh(1), ash(1), ...). if [ "`id -u`" -eq 0 ]; then # id -u 显示登录用户id,0是root用户 PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" else PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games" fi export PATH # 下面的判断语法是否是很熟悉呢? # 这里主要进行PS1这个环境变量的设置,主要影响交互式命令号行头标示符 if [ "${PS1-}" ]; then if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then if [ -f /etc/bash.bashrc ]; then # 到这里就是判断当前是否是不是使用sh且存在bash.bashrc文件 . /etc/bash.bashrc fi else # sh模式(不是bash模式),就是所谓的POSIX兼容模式 if [ "`id -u`" -eq 0 ]; then PS1='# ' else PS1='$ ' fi fi fi if [ -d /etc/profile.d ]; then # 第一个判断文件夹是否存在 for i in /etc/profile.d/*.sh; do # 遍历文件夹中的每一个文件 if [ -r $i ]; then # 判断单个文件是否存在,执行 . $i fi done unset i fi
下面针对用户环境变量设置是按顺序,找到的就会执行,没找到就不执行:
通常状况下,会只存在一个。例如,Debian系统下面,用户目录下面只有.profile。但是内部又调用执行类另一个同目录的文件:.bashrc。下面是真是的源码:
# ~/.profile: executed by Bourne-compatible login shells. if [ "$BASH" ]; then # 若是BASH变量存在就执行这个代码块 if [ -f ~/.bashrc ]; then # 若是.bashrc这个文件存在在用户目录中,就执行这个代码块 . ~/.bashrc # 这种的另外一种写法是:source ~/.bashrc fi fi mesg n || true
# ~/.bashrc: executed by bash(1) for non-login shells. # 这里都注释掉了,认真阅读可见,咱们平时经常使用的命令简写都出自这里,只不过这个系统定制性的给去掉了 # Note: PS1 and umask are already set in /etc/profile. You should not # need this unless you want different defaults for root. # PS1='${debian_chroot:+($debian_chroot)}\h:\w\$ ' # umask 022 # You may uncomment the following lines if you want `ls' to be colorized: # export LS_OPTIONS='--color=auto' # eval "`dircolors`" # alias ls='ls $LS_OPTIONS' # alias ll='ls $LS_OPTIONS -l' # alias l='ls $LS_OPTIONS -lA' # # Some more alias to avoid making mistakes: # alias rm='rm -i' # alias cp='cp -i' # alias mv='mv -i'
对于平常的使用,最多见的莫过于字符串拼接,与数字的运算,下面分别来讲说这两方面
#!/bin/bash str1=hello str2=shell str3=world echo $str1$'\t'$str2$'\t'$str3 # 输出为:hello shell world
$'string'这种类型的值会被特殊解析。这种值,内部使用反斜杠加一个字符,都会按照标准c的模式进行转义。若是存在这种反斜杠转义序列, 映射关系以下: /a 警告(铃声) /b 退格 /e 一个转义字符 /f 换页 /n 换行 /r 回车 /t 水平制表符 /v 垂直制表符 // 反斜杠 /' 单引号 /nnn 八进制 /xHH 十六进制 /cx 控制x字符(没弄明白这个何时用)
shell自己就是万物皆字符串,因此对于纯数学计算支持的不是很好。大致上分两大类:整数运算与浮点数运算。实践的方式有三种,前两种是整数运算,最后一种是浮点数运算
#!/bin/bash # An example of using the expr command var1=10 var2=20 var3=$(expr $var2 / $var1) echo The result1 is $var3 var3=$(expr $var2 \* $var1) echo The result2 is $var3
这东西很差使用,并且是很是。其中还会支持以下的一些操做:
这东西,若是是取结果值,赋值给其余变量的话,通过实际的测验,还有一些猫腻,请仔细看下面代码与注释:
#!/bin/bash # 测试expr取值操做 expr $var \| 3 #若是是没被赋值参与了运算的,这时候会报错 $var= expr $var \| 3 #这种被赋了个空值,也会报错 $var=1 expr $var \| 3 #这种才不会报错,按照正常逻辑返回值:1 $var= expr "$var" \| 3 #这种也不会报错,直接取了var的空值,结果为:3 expr 3 | 2 #不转义“或”符号报错,shell会当作管道符号处理,而2并非命令 expr 4\*3 #这种直接返回结果:4*3(字符串) expr 4\* 3 #这种语法错误,操做符的两边必需要有空格
可见shell下面的算术运算操做并不容易,很是多的小细节,恩就是所谓的“奇技淫巧”!
中括号主要是为了取代expr而出现的,主要也是用于整数的算术运算与逻辑运算,而且可以方便的取值操做。毕竟,使用expr有太多奇技淫巧,太多要注意的语法细节了,而中括号,偏偏能很好的解决这些。下面是一些语法举例:
#!/bin/bash # 中括号算术运算举例 [4*4] #单独这样会有语法错误,由于中括号语法要配合$来使用,报错信息:[4*4]:未找到命令 [ 4*4 ] #这种其实没有语法错误,中括号里面两边有了空格这种,属于判断语句,下面会介绍到 [4 * 4] #这种操做符有了空格,会被命令解释器拆分红三个命令:[四、*、4],而[4并非命令,因此报错 $[4*6] #这种表达式自己是没问题的,可以求结果,但是结果求出来了shell会运行结果,显然24不是命令,报错 var=$[3 *4] #这种是最正确的,操做符左右不用担忧空格、也不用担忧转义问题,求结果,并赋值操做
仔细阅读上面注释,就能够了。是否是感受shell很是死扣一些细节?这个脚本语言就这个德行!
恩,最后了,一步步闯关以后,这东西是“公主”!最好控制的东西(就是奇技淫巧少)。好控制不表明好用,来看看bc两种模式
bash计算器其实是一种编程语言,它容许在命令行中输入浮点表达式,而后解释并计算该 表达式,最后返回结果。bash计算器可以识别:
下面是我一顿瞎几把搞的代码:
jicheng:~/Project/shell_test$ bc -q #q是不显示软件介绍 34.5 23*34.645645 796.849835 234*3-(3/ 234)#支持混合运算 702 3/ 234 0 3.0/ 234.023 0 scale= 6 #默认是0,不设置,小于1的除法结果显示0 3.0/ 234.023 .012819 3/ 234 .012820 var1=10 #内部支持变量 var1 * 4 40 var2 = var1 / 5 print var2 2 quit jicheng:~/Project/shell_test$
基本语法为:variable=$(echo "options; expression" | bc)
#!/bin/bash var1=100 var2=45 var3=$(echo "scale=4; $var1 / $var2" | bc) # 看到如何设置精确值 echo The answer for this is $var3
这两个话题也是一大难。哎~难点在于不少不少的细节,仍是那样,难在正所谓的"奇技淫巧",咱们分开2小节来说:
对于一个计算机语言来讲,输入,无非就是:用户交互式输入与文件内容的输入。Shell里面也同样。针对用户的输入,能够从命令传入,也可实时读取用户的外设输入。而针对这些个输入,shell会有相应的读取与保存方式,下面分开来介绍
在执行命令时候,默认以空格分割,紧接着在命令后面进行传入的连续字符串。分割方式是空格,若是入参自己带空格,要使用引号或者双引号,进行引用包裹
#!/bin/bash # ./shell_test var1 var2 var3 #正确获取文件名的真实写法 echo `basename $0` echo $1 echo $2 echo $3 # 一共有多少个入参 echo $# # 最后一个入参 echo ${!#}
大部分知识都在上面变量小节介绍过了,上面关键的是最后两行代码:
有时候,咱们会动态获取输入参数,并循环作处理,例以下面的方式:
#!/bin/bash # shell_test.sh文件 count=1 for var in "$@" do echo "Parameter #$count: $var" count=$[ $count + 1 ] done # 运行:./shell_test var1 var2 # 结果: # Parameter #1: var1 # Parameter #2: var2
很简单。再高一个难度:若是咱们想对入参进行分类,区分配置选项与输入参数两种,例如咱们常用的
ls -al
不就是有配置选项al。看下面咱们怎么用实际的代码进行实现:
#!/bin/bash # shell_test.sh文件 while [ -n "$1" ] do case "$1" in -a) echo "Found the -a option";; -b) echo "Found the -b option";; -c) echo "Found the -c option";; *) echo "$1 is not an option";; esac shift done <<COMMENT 输入 /shell_test.sh -a -c -b -d 结果: Found the -a option Found the -c option Found the -b option -d is not an option COMMENT
shift是shell内部的一个命令,能够左移一个输入参数,被移动的入参,将会消失,例如,入参有var一、var2,shift以后,入参只有var2。shift能够有参数,后面加上一个数字,表示要左移多少个参数。上面的代码用到告终构化的语句,后面章节会进行介绍。接下来咱们再高一个级别:我不只仅想要配置选项的入参,我还想要配置参数的入参,那咱们怎么定义呢?针对输入方式,咱们能够用一个特殊字符来隔离选项与参数,例如'—',看下面:
#!/bin/bash # shell_test.sh while [ -n "$1" ] do case "$1" in -a) echo "Found the -a option";; -b) echo "Found the -b option";; -c) echo "Found the -c option";; # 这里作了特殊处理:shift掉了--入参,并结束while循环 --) shift break ;; *) echo "$1 is not an option";; esac shift done count=1 for var in "$@" do echo "Parameter #$count: $var" count=$[ $count + 1 ] done <<COMMENT 输入:./shell_test.sh -a -b -c -- var1 var2 var3 输出: Found the -a option Found the -b option Found the -c option Parameter #1: var1 Parameter #2: var2 Parameter #3: var3 COMMENT
已经有点规模了,哈哈。接下来咱们还想进一步,ls -al
相似于这种,人家成熟的命令但是能够合并配置选项的,但是上面的代码并不支持。接下来就是最终的解决方案,要用到一个很好的命令:getopts。下面是代码,边写边解说:
#!/bin/bash while getopts :ab:c opt do case "$opt" in a) echo "Found this -a option";; b) echo "Found this -b option,with value $OPTARG";; c) echo "Found this -c option";; *) echo "Unknow";; esac done shift $[ $OPTIND -1 ] count=1 for param in "$@" do echo "Parameter $count: $param" count=$[ $count+1 ] done <<COMMENT 输入:./shell_test -ab var1 -c var2 var3 输出: Found this -a option Found this -b option,with value var1 Found this -c option Parameter 1: var2 Parameter 2: var3 COMMENT
一波解释:
至此咱们对于命令传参式输入就全介绍完了,下面开始说用户交互式输入
这种比较简单一些,就是用read这个命令一顿瞎几把搞~直接上代码,直接解释:
#!/bin/bash # 最基本的read,阻塞式的输入,用echo的n(不换行)参数配合打印提示行 echo -n "Enter your name: " read name echo "Hello $name, welcome to my program. " # 使用read的p参数,直接打印提示航 read -p "Please enter your age: " age days=$[ $age * 365 ] echo "That makes you over $days days old! " # 使用read的t参数,来进行超时控制,单位是秒 if read -t 5 -p "Please enter your name: " name then echo "Hello $name, welcome to my script" else echo "Sorry, too slow! " fi # 使用read的s参数,能够隐藏输入的字符,好比密码输入 read -s -p "Enter your password: " pass echo "Is your password really $pass? "
文件中的输入,主要仍是运用read这个命令,也是直接代码:
#!/bin/bash # reading data from a file # count=1 # test是一个文本文件 cat test | while read line do echo "Line $count: $line" count=$[ $count + 1] done echo "Finished processing the file"
line是记录了每一行的记录,咱们能够根据需求,继续对每行的数据进行切割处理
在shell中,输出永远和重定向脱不开干系,由于在shell中不管是输出到屏幕(标准输出)或是输出到文件,都是要靠重定向标准输出来 实现的,因此掌握各类重定向的方式,很关键,一样,这里也是好几种“奇技淫巧”的方式进行重定向。下面我分别说说几个方面。
在运行shell脚本的时候,会有一系列的文件描述符,用数字表示,最多有9个,最多见的就是系统设定好的前三个:
咱们能够重定向这几个,同时也能够本身建立新的文件描述符:
#!/bin/bash # 默认状况的echo,直接输出到标准输出 echo "echo 2 STDOUT" # 咱们能够进行重定向标准输出,这样就会输出到具体的文件当中去 echo "echo 2 other" >test.out ## 双大于号的输出表示追加到一个文件,不是覆盖 echo "echo 2 other" >>test.out # 下面的jiad是没有的目录,标准错误会输出到屏幕 ls /jiad # 对标准错误输出进行重定向,直接在大于号前面加数字 ls /jiad 2>test.out # 全局性永久重定向,使用exec命令原理是启动一个新的shell而后进行重定向 exec 2>test.out ls /jiad #这种错误会直接输出到test.out文件,由于标准错误全局性的重定向了 # 这种就是自定义文件描述符3,而后重定向到test.out文件 exec 3>test.out # 引用文件描述符的方式,这样输出的结果就覆盖到了test.out文件里面了 echo "echo 2 other" >&3
上面主要的语法都已经列出来,仔细阅读注释就能够了。另外,这地方对重定向的箭头左右是否有空格,要求不是特别的严格,有没有功能都不会受影响,请放心使用。
当咱们使用exec命令永久性的重定向了标准输出的话,如何再重定向回来本来的呢?也很简单,就如咱们最开始学习编程时候学的“三段式”交换数字同样,先暂存,再操做,最后再反赋值就能够了,就以下面:
#!/bin/bash exec 3 >&1 exec 1 >test.out echo "temp save file description" # 看到没?直接把1再重定向会3,3里面,最开始是重定向到标准输出的 exec 1 >&3
输入的文件 标示符是0,重定向使用小于号,简单的一个重定向代码以下:
#!/bin/bash # 0和符合之间不能有空格,其实他们是一体的,表示:0文件描述符输入重定向 exec 0< out # 这种状况,cat并不会进行交互式输入了,而会从out文件进行输入 cat
一样,咱们能够经过暂存的方式进行恢复重定向的标准输入
#!/bin/bash # 下面的小于号左右不能有空格存在,不然语法报错,&符号与前面不能有空格 exec 3<&0 exec 0<out # 这里的cat的输入已经变成了out文件 cat # 这个命令能够查询0,1,2,3几个文件描述符的指向文件 lsof -a -p $$ -d 0,1,2,3 # 恢复标准输入的文件描述符 exec 0<&3 lsof -a -p $$ -d 0,1,2,3 # 这个时候会变成交互式输入 cat
在输入重定向这里,有个"奇技淫巧",就是咱们可以脚本中动态设置标准输入(重定向),而不用非得使用原生的标准输入或是文件输入,语法以下:
command << delimiter document delimiter
具体咱们举一个例子:
#!/bin/bash # read file and create INSERT statements for MySQL outfile='members.sql' IFS=',' while read lname fname address city state zip do # 注意这个地方 cat >> $outfile << EOF INSERT INTO members (lname,fname,address,city,state,zip) VALUES ('$lname', '$fname', '$address', '$city', '$state', '$zip'); EOF done < ${1}
上面的cat,实际上是直接在命令行执行cat这种模式的,只不过在执行的时候,重定向了两个东西:
颇有意思,这种方式,很普遍被运用,例如:shell脚本对mysql数据库执行一条sql语句
说到了最后,这一章说完,几乎shell的语法部门就结束了。剩下的,就是深刻大海般的”命令海“!这些命令,有系统自带的,也有咱们本身安装的工具带的命令,或是咱们安装的软件带来的命令,例如git、docker等。针对结构化的问题,也算是放轻松了,由于结构化的语法,是平时咱们最最多见的了。
这两个东西,在任何计算机语言体系中,可谓是老生常谈了。很少说,下面是基本语法,有两种模式:
# 第一种模式 if command then command1 command2 ...... fi # 第二种模式 if command; then command1 command2 ...... fi # 多级别的ifelse if command1 then commands elif command2 then more commands else more commands fi
特别注意点:shell中没有所谓的判断真(true)假(false)一说,这里的if语句中的判断语句是一个具体的命令(command)。根据命令的执行退出的状态值来判断是否要执行if里面的代码块: 若是这个命令正确执行,那退出值为0,if代码块就被执行;若是命令执行过程当中发生错误,退出值就不为0,那if代码块就不被执行。这就是shell中的语法。后面的while、for、util等都是这种规则
下面就是基本的shell中if语句的代码:
#!/bin/bash # Testing nested ifs - use elif & else # testuser=NoSuchUser if grep $testuser /etc/passwd then echo "The user $testuser exists on this system." elif ls -d /home/$testuser then echo "The user $testuser does not exist on this system." echo "However, $testuser has a directory." else echo "The user $testuser does not exist on this system." echo "And, $testuser does not have a directory." fi
虽然ifelse的判断语句是运行一个命令,而后根据退出值来判断的,可是能不能让咱们仍是像以往那样,根据语句的真假来判断是否执行语句块呢?恩,test命令就是解决这个问题的:
if test condition then commands fi
#!/bin/bash my_var='jicheng' if test $my_var then # 这个会被执行,由于test命令会让退出值为0 echo "myvar" fi my_null_var="" if test then # 空的test的退出值不为0,因此这个地方不会被执行 echo "1" elif test my_null_var then # test空串也是会退出值不为0的,因此这里也不会执行 echo "2" else echo "3" fi
固然,shell中不会傻呵呵让你一直写test的,提供了一个替换语法:
# 注意这里:中括号内部的condition两边必需要有空格,不然语法有错,上面立的flag,在这里能够拔下来了 if [ condition ] then commands fi
针对性的,test的语法,能够对三种类型进行条件判断下面分三个小节
因为shell中万物皆字符串,因此对于数值的比较,要使用关键字进行,不难,下面就是:
下面是简单的例子:
#!/bin/bash value1=10 value2=11 # if [ $value1 -gt 5 ] then echo "The test value $value1 is greater than 5" fi # if [ $value1 -eq $value2 ] then echo "The values are equal" else echo "The values are different" fi
注意shell中只能处理整数,对于浮点数的test,会报错。不支持
其实也不难,主要注意和sort的区别。下面是基础的一些字符串比较表达式:
注意点有几个:
[ "test" \> "Test" ]
下面是简单的测试代码:
#!/bin/bash # testing string sort order val1=Testing val2=testing # if [ $val1 \> $val2 ] then echo "$val1 is greater than $val2" else echo "$val1 is less than $val2" fi
最后一类比较测试颇有多是shell编程中最为强大、也是用得最多的比较形式。它容许你测 试Linux文件系统上文件和目录的状态:
#!/bin/bash if [ -d $HOME ] && [ -w $HOME/testing ] then echo "The file exists and you can write to it" else echo "I cannot write to the file" fi
双小括号模式是(用于算术运算比较):
(( expression ))
支持:var++、var--、++var、--var、!(非)、~(位求反)、**(幂运算)、<<(左移)、>>(右移)、&(位与)、|(位或)、&&(逻辑与)、||(逻辑或)。另外这种模式下大于小于号不用转义!
双中括号的模式是(用于字符串比较):
[[ expression ]]
双方括号里的expression使用了test命令中采用的标准字符串比较。但它提供了test命 令未提供的另外一个特性——模式匹配(pattern matching)。
#!/bin/bash if [[ $USER == r* ]] then echo "Hello $USER" else echo "Sorry, I do not know you" fi
多说两句:在这里,对于这两个东西,能够玩的花样有点多,平常使用的也会总去使用这两个运算符的花样,这个我在后面单独开文章细讲”奇技淫巧“!
通常高级静态语言中,都有switch的语法,shell中也有。不过这里的使用方式,有点"诡异":
case variable in pattern1 | pattern2) commands1;; pattern3) commands2;; *) default commands;; esac
和Java中不一样,这里每一个匹配了但括号里面的模式并执行了command以后,就结束case语句了,并且使用两个;符号结尾。而Java中不使用break的话,会一直匹配下面全部的模式并执行里面代码块。
#!/bin/bash # using the case command # case $USER in rich | barbara) echo "Welcome, $USER" echo "Please enjoy your visit";; testing) echo "Special testing account";; jessica) echo "Do not forget to log off when you're done";; *) echo "Sorry, you are not allowed here";; esac <<COMMENT 输出: Welcome, rich Please enjoy your visit COMMENT
for语句在shell中,有两种方式,一种是原生的,一种是C语言风格的。可是C风格的for语句,在一些bash中并非很支持(ubuntu16中的dash就不支持),因此我看,大部分仍是使用原生的for语句为主,咱们这里就先不讲C风格的for。原生的for,在一些小细节上面仍是要注意的,下面是基本的语法:
for var in list do commands done
#!/bin/bash for var in I don't know if this'll work do echo "$var" done
结果是:
I
dont know if thisll
work
显然不符合咱们的预期,由于shell把两个引号中间的部分当作一个字符串了,有两种解决方法:
#!/bin/bash # 一种进行转义,一种使用双引号括起来 for var in I don \'t know if "this'll" work do echo "$var" done
#!/bin/bash for var in Nevada New Hampshire New Mexico New York do echo "Now going to $var" done
结果是:
Now going to Nevada
Now going to New
Now going to Hampshire
Now going to New
Now going to Mexico
Now going to New
Now going to York
Now going to North
Now going to Carolina
显然就不符合。咱们可使用双引号括起来:
#!/bin/bash for var in Nevada "New Hampshire" "New Mexico" "New York" do echo "Now going to $var" done
#!/bin/bash # reading values from a file file="states" IFS=$'\n' for state in $(cat $file) do echo "Visit beautiful $state" done
这样,对于文件中的分割,只会使用换行符
#!/bin/bash for file in /home/rich/test/* do if [ -d "$file" ] then echo "$file is a directory" elif [ -f "$file" ] then echo "$file is a file" fi done
注意使用双引号括起来了文件名的引用变量,是由于有可能文件名有空格,若是不括起来,语法就会有错误了!
经历了前面的if与for的历练,对于while这里的语法相对来讲就没有那么难理解了:
while test command do other commands done
简单的例子:
#!/bin/bash var1=10 while [ $var1 -gt 0 ] do echo $var1 var1=$[ $var1 - 1 ] done
这个和while的逻辑相反:while是知道test退出码为非零的时候,结束循环,而这个是当test循环退出码为零的时候结束循环,语法也是相似:
until test command do other commands done
例子不举了
到此几乎最最基本的shell语法就差很少都讲了。剩下的,就是如"汪洋"的命令大军了。哪怕是这些基础的语法,我都感受,是由命令组成的,这就是shell编程,疯狂的奇技淫巧~接下来我会短平快的写几个小案例和shell中经常使用的命令,例如awk,sed,find等,如如有具体的语法”灵光一现“,都会update到本篇幅中,恩就这样。