一. 创建交互式脚本

使用 echo命令的选项

关于各种命令的使用,可以使用man 命令来查看命令的详细用法介绍。例如,我想看下 echo 的用法和各种选项。可以执行 man echo。执行结果如下:

如果单独执行 echo 命令,就会打印出一个空白行。

默认情况下,echo 都会换行,如果不想换行的话,可以使用下面两种方式的一种。

echo -n "Which directory do you want to use? "
echo -e "Which directory do you want to use? \c"

使用 read 命令

如果我们需要读入用户输入的参数时,可以使用 read 命令,当然还可以从文件系统等读入信息。

我们建立一个新的脚本文件 hello3.sh。

#!/bin/bash
echo -n "Hello I $(basename $0) may I ask your name: "
read
echo "Hello $REPLY"
exit 0

执行此脚本时,首先提示需要输入,然后输入的内容,REPLY当没有给read提供参数时设置,最后打印出来。

执行结果为:

优化 read 提示的脚本

在前面的例子中,我们使用了echo -n的方式来阻止信息换行,其实 read 命令也带了一个选项来实现相同的功能:

read -p "Enter your name: " name

上面的脚本中,我们定义了一个变量name用来保存输入的内容,如果不定义变量的话,输入的内容会保存在REPLY中。

下面是具体使用的语法:

hello3.sh的脚本可以改成如下:

#!/bin/bash
read -p "May I ask your name: " name
echo "Hello $name"
exit 0

限制输入内容的个数

我们还可以使用 read命令的-n 选项,此选项后面需要接一个数字,可以限制输入内容的个数。

#!/bin/bash
read -p "May I ask your name: " name
echo "Hello $name"
read -n1 -p "Press any key to exit"
echo
exit 0

控制输入内容的可见性

目前,我们输入的内容都是可见的,但有些敏感的数据,如密码,信用卡号等信息,输入时并不想可见。那么可以使用read -s

这时再输入时,就有一个钥匙的标识,而且输入时不可见。

实例演示

现在有一个小程序,要求把指定后缀的文件备份到指定的目录下,代码如下:

#!/bin/bash
# Script to prompt to back up files and location
# The files will be search on from the user's home
# directory and can only be backed up to a directory within $HOME read -p "Which file types do you want to backup " file_suffix
read -p "Which directory do you want to backup to " dir_name # The next lines creates the directory if it does not exist
test -d $HOME/$dir_name || mkdir -m 700 $HOME/$dir_name # The find command will copy files the match the
# search criteria ie .sh . The -path, -prune and -o
# options are to exclude the back directory from the
# backup.
find $HOME -path $HOME/$dir_name -prune -o \
-name "*$file_suffix" -exec cp {} $HOME/$dir_name/ \; exit 0

二. 条件判断语句

使用test 内建函数

test命令是 shell 环境中用于测试条件表达式的工具。

它的返回值可以是 true,false,0或1。基本语法为:

test EXPRESSION

如果我们需要多个表达式,可以使用ANDOR,对应的选项为-a-o

test EXPRESSION -a EXPRESSION
test EXPRESSION -o EXPRESSION

其实,在实际应用中,test 有种非常简洁的方式,就是被中括号包含的条件表达式。这种方式更加常用。语法如下:

[ EXPRESION ]

test 的用法很多,例如,可以比较两个字符串是否相等:

[ $USER = root ]

我们还可以test 的选项来判断一个字符串的长度是否为0。

[ -z $1 ]

上面的代码的含义是,如果没有参数输入的话,返回 true。

test 还可以用来比较数字的大小。例如:

[ $# -gt 0 ]

除此而外,还可以判断文件的类型。例如,我们想查找类型为符号链接的文件,然后删除。可以使用如下脚本:

# [ -h $HOME/bin ] &&rm $HOME/bin

其他常用的选项如下:

  • -d:文件是否为目录
  • -e:文件是否存在
  • -x:文件是否可以执行
  • -f:文件是否为常规文件
  • -r:文件是否可读
  • -p:文件是否为命名管道
  • -b:文件是否为块设备文件
  • -c:文件是否为字符设备文件

使用 if 条件判断语句

if 语句的基本格式为:

if conditon ; then
statement 1
statement 2
fi

我们可以看一个具体的例子:

#!/bin/bash
if [ $# -lt 1 ] ; then
echo "Usage: $0 <name>"
exit 1
fi echo "Hello $1" exit 0

在运行此脚本时,如果没有输入参数,则提示正确的使用方法,非正常退出;否则,打印输入的参数,程序正常退出。

if 语句还可以使用 else 条件分支。具体的语法为:

if conditon ; then
statement
else
statement
fi

我们新建一个脚本文件 hello6.sh,来展示 if else 的用法。

#!/bin/bash
if [ $# -lt 1 ] ; then
read -p "Enter a name: "
name=$REPLY
else
name=$1
fi echo "Hello $name" exit 0

当没有输入参数时,程序提示需要输入一个 name;如果输入了的话,就会打印出来。

最后一种 if 的情况,也是最完整的 if 条件语句。语法如下;

if condition; then
statement
elif condition; then
statement
else
statement
fi

再举个例子,新建脚本 backup2.sh,我们使用 tar 命令来备份压缩指定的目录,根据输入的参数“H”,“M”,“L”,可以执行不同的压缩级别。

如果输入的参数为“H”,则使用 bzip2的压缩方式;

如果输入的参数为“M”,则使用 gzip 的压缩方式;

如果输入的参数为“L”,则使用 tar 命令对文件打包,不压缩。

#!/bin/bash
# this sciprt dirs’ location are defualt under $HOME read -p "Choose H, M or L compression " file_compression
read -p "Which directory do you want to backup to " dir_name
read -p "Which directory do you went to backup: " tobe_backup_name # The next lines creates the directory if it does not exist
test -d $HOME/$dir_name || mkdir -m 700 $HOME/$dir_name
backup_dir=$HOME/$dir_name tar_l="-cvf $backup_dir/b.tar $HOME/$tobe_backup_name"
tar_m="-czvf $backup_dir/b.tar.gz $HOME/$tobe_backup_name"
tar_h="-cjvf $backup_dir/b.tar.bzip2 $HOME/$tobe_backup_name" if [ $file_compression = "L" ] ; then
tar_opt=$tar_l
elif [ $file_compression = "M" ]; then
tar_opt=$tar_m
else
tar_opt=$tar_h
fi tar $tar_opt exit 0

使用 case 选择语句

如果 if else 分支太多的话,可以考虑使用 case 语句,case 语句提供了更加简洁的机制。

case 语句的语法结构为:

case expression in
case1)
statement1
statement2
;;
case2)
statement1
statement2
;;
*)
statement1
;;
esac

还是举个简单的例子,新建脚本文件 grade.sh。

#!/bin/bash
# Script to evaluate grades
# Usage: grade.sh studentName grade if [ ! $# -eq2 ] ; then
echo "You must provide <studentName> <grade>
exit 2
fi case $2 in
[A-C]|[a-c])
echo "$1 is a star pupil"
;;
[Dd])
echo "$1 needs to try a little harder!"
;;
[E-F]|[e-f])
echo "$1 could do a lot better next year"
;;
*)
echo "Grade could not be evaluated for $1"
esac exit 0

运行结果如下:

三. 一些注意事项

我们前面已经介绍过 test 内置命令用来判断条件语句,但通常我们会推荐使用[]来替代 test 命令。例如:

[ -f /etc/hosts -a -r /etc/hosts ]

但这里面有个问题,例如,下面的脚本中,文件名中有空格,我们都知道,空格在命令行中有特殊的用处,用来分割命令选项和参数等。下面的代码会报错。

FILE="my file"
[ -f $FILE -a -r $FILE ] && cat $FILE

报错信息为“too many arguments”,原因是程序把带有空格的文件名解析成了两部分。

而这时,我们需要把变量用双引号包含起来,

FILE="my file"
[ -f "$FILE" -a -r "$FILE" ] && cat "$FILE"

那有没有好的办法可以不使用双引号呢?当然有的,那就是使用“[[”关键字。

“[[”并不是所有的 shell 都支持,它不兼容Bourne Shell。我们可以用 type 命令来查看它的类型。

上面的脚本中的[]内的双引号就可以不用了,但要注意的是 cat 里的双引号还是要有的。

FILE="my file"
[[ -f $FILE && -r $FILE ]] && cat "$FILE"

“[[”还有其他高级的功能:

1. 模式匹配

例如,我们需要判断 Perl 脚本,然后做其他的操作,那么就可以这样写:

[[ $FILE = *.pl ]] && cp "$FILE" scripts/
2. 正则表达式

我们可以使用“=~”来匹配正则表达式。我们可以用正则表达式重写上面的脚本。

$ [[ $FILE =~ \.pl$ ]] &&cp "$FILE" scripts/

我们还可以使用“(())”运算符来做一些简单的运算。

1. 简单的数学运算

我们可以使用“((”做一些简单的数学运算,它可以替代 let 这个内置命令。下面两行的代码执行结果是一样的。

a=(( 2 + 3 ))
let a=2+3
2. 用在循环累加或累减中

这种方式更加常用,

COUNT=1
(( COUNT++ ))
echo $COUNT
3. 用于运算检查中

我们也可以把“((”用在 test 判断条件中,我们可以是用“>” 符号,来替代“-gt”。

(( COUNT > 1 )) && echo "Count is greater than 1"

四. 迭代循环

循环语句是任何一门语言都不能缺失的部分。shell 里也是一样,只是语法不太一样。如果学过其他的编程语言,就很容易掌握。

1. for 循环

for 循环的语法疾结构为:

for f in * ; do
statement "$f"
done

这里的 f 就是迭代的元素,* 可以是一个数组或是 list,也可以是命令管道。

还有另外一种写法:

for f in *
do
statement "$f"
done

可以根据自己的喜好选择一种写法。

新建一个脚本文件,打印出所有输入的参数:

#!/bin/bash
echo "You are using $(basename $0)"
for n in $*
do
echo "Hello $n"
done exit 0

运行结果如下:

在循环中,可以使用continuebreak关键字,具体用法与其他语言里是一样的。continue表示在循环体内,跳过当前循环,执行下次的循环;而break表示退出整个循环,后面的循环和代码不再执行。

看具体看例子。

$ for f in * ; do
[ -d "$f" ] || continue
chmod 3777 "$f"
done

如果是目录,添加权限;如果不是,跳过当前循环,continue 后面代码不再执行,而是直接执行下次循环。

$ for f in * ; do
[ -d "$f" ] && break
done echo "We have found a directory $f"

上面的脚本,在循环中一旦发现目录,则立即停止循环并退出。

2. while 循环

while 循环可以说是 for 循环的一个变体,只要特定条件为真,while 语句就会执行。具体看例子,

COUNT=10
while (( COUNT >= 0 )) ; do
echo -e "$COUNT \c"
(( COUNT-- ))
done ; echo

3. until 循环

until循环与while语句的功能正好相反:只要特定条件为假,它就重复。下面是一个与前面的 while 循环具有同等功能的 until 循环。

COUNT=10
until (( COUNT < 0 )) ; do
echo -e "$COUNT \c"
(( COUNT-- ))
done ; echo

4. 实例练习

现在,我们做一个用户选择界面,这样,根据提示输入不同的参数来执行不同的功能,这里我们需要用到while循环,和前面讲过的case条件选择。

#!/bin/bash

while true ; do
clear
echo "Choose an item: a, b or c"
echo "a: Backup"
echo "b: Display Calendar"
echo "c: Exit" read -sn1
case "$REPLY" in
a) tar -czvf $HOME/backup.tgz ${HOME}/JavaSource;;
b) cal;;
c) exit 0;;
esac
read -n1 -p "Press andy key to continue"
done

根据提示,如果输入 a 的话,则把 home 目录下的 JavaSource 目录压缩打包。

输入b,显示当前月份。

输入c,程序退出。

Linux Shell——流程控制的更多相关文章

  1. linux shell 流程控制(条件if,循环【for,while】,选择【case】语句实例 --转载

    http://www.cnblogs.com/chengmo/archive/2010/10/14/1851434.html nux shell有一套自己的流程控制语句,其中包括条件语句(if),循环 ...

  2. linux shell 流程控制

    导读 和Java.PHP等语言不一样,linux shell有一套自己的流程控制语句,其中包括条件语句(if),循环语句(for,while),选择语句(case).下面我将通过例子介绍下,各个语句使 ...

  3. [转]linux shell 流程控制(条件if,循环【for,while】,选择【case】语句实例

    原文链接:http://www.cnblogs.com/chengmo/archive/2010/10/14/1851434.html linux shell有一套自己的流程控制语句,其中包括条件语句 ...

  4. Shell 流程控制-if for case while until break continue

    Shell 流程控制 和Java.PHP等语言不一样,sh的流程控制不可为空,如(以下为PHP流程控制写法): <?php if (isset($_GET["q"])) { ...

  5. 九、Shell 流程控制

    Shell 流程控制 和Java.PHP等语言不一样,sh的流程控制不可为空,如(以下为PHP流程控制写法): <?php if (isset($_GET["q"])) { ...

  6. linux shell学习之shell流程控制

    在linux shell编程中,流程控制结构与语句,也算是shell脚本中的重点了,不了解的朋友,跟随脚本小编一起来学习下吧. linux控制流结构学习. 一,shell控制流结构 1.控制结构   ...

  7. 『忘了再学』Shell流程控制 — 33、if条件判断语句(一)

    目录 1.单分支if条件语句 2.双分支if条件语句 (1)示例1 (2)示例2 什么是流程控制? 普通理解:Shell编写的程序是顺序执行的,也就是说第一命令先执行,然后接着执行第二条命令,然后再下 ...

  8. Linux Shell 流程控制语句

    * 本文主要介绍一些Linux Shell 常用的流程控制语句* 1. if 条件语句:if-then/if-elif-fi/if- else-fi if [条件判断逻辑1];then command ...

  9. 吴裕雄--天生自然ShellX学习笔记:Shell 流程控制

    和Java.PHP等语言不一样,sh的流程控制不可为空,如(以下为PHP流程控制写法): <?php if (isset($_GET["q"])) { search(q); ...

随机推荐

  1. 微信企业号接收消息(使用SpringMVC)

    微信企业号接收消息(使用SpringMVC) 微信企业号接收消息(使用SpringMVC) 将应用设置在回调模式时,企业可以通过回调URL接收员工回复的消息,以及员工关注.点击菜单.上报地理位置等事件 ...

  2. 自学 iOS - 三十天三十个 Swift 项目 第一天

    最近公司项目不是很忙,偶然间看到编程语言排行榜,看到swift 已经排到前10了,然OC排名也越来越后了,感觉要上车了,虽然现在项目都是用OC写的,但是swift是一种趋势.在网上看到"自学 ...

  3. Microsoft Visual Studio 2017 安装过程

    工欲善其事必先利其器 Visual Studio 2017 正式版官方下载地址:https://www.visualstudio.com/downloads/ 安装vs2017的时候最好关闭已打开的v ...

  4. Struts 基本概念,优点及不同版本之间的关系

    strutx 1.x struts 是 apache 基金会的一个开源项目. struts 是一套实现 MVC的框架. MVC = 程序分层设计的思想 = Model(数据访问层1) / View(视 ...

  5. CSS规范 - 命名规则

    使用类选择器,放弃ID选择器 ID在一个页面中的唯一性导致了如果以ID为选择器来写CSS,就无法重用. NEC特殊字符:"-"连字符 "-"在本规范中并不表示连 ...

  6. ELK5.0安装教程

    ELK升级后,安装稍微发生了点变化,在Elasticsearch中增加了很多资源上的限制,其他的倒是没什么变化.不过所有的安装都是基于JDK已经安装完的情况,且为1.8版本. 安装Elasticsea ...

  7. ArcGIS API For JavaScript 加载地图,设置地图中心点

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  8. 【SF】开源的.NET CORE 基础管理系统系列导航

    SF是一套基于ASP.NET Core MVC+EFCore+Bootstrap开发出来的基础管理系统,源代码完全开源,可以帮助你解决C#.NET项目中重复编码的繁琐工作,让开发人员远离加班! SF ...

  9. cuda线程/线程块索引小结

    内建变量: threadIdx(.x/.y/.z代表几维索引):线程所在block中各个维度上的线程号 blockIdx(.x/.y/.z代表几维索引):块所在grid中各个维度上的块号 blockD ...

  10. Java:从面试题“i++和++i哪个效率高?"开始学习java字节码

    今天看到一道面试题,i++和++i的效率谁高谁低. 面试题的答案是++i要高一点. 我在网上搜了一圈儿,发现很多回答也都是同一个结论. 如果早个几年,我也会认同这个看法,但现在我负责任的说,这个结论是 ...