Linux Shell简明教程(一)

系列文章首发平台为果冻想个人博客。果冻想,是一个原创技术文章分享网站。在这里果冻会分享他的技术心得,技术得失,技术人生。我在果冻想等待你,也希望你能和我分享你的技术得与失,期待。

神奇的Linux

Linux有多神奇,我就不说了。作为在一个IT界混的码农,或多或少的都会接触Linux,不管你是怎么接触Linux,对于其中的一些命令肯定也会或多或少的了解一些。Linux虽然不是你的必须装备,但是装备上了Linux,对于你的职业生涯肯定是有百利而无一害的。基于此,我接触了Linux,然后就学习了一下Shell脚本,以此文章,作为Shell脚本学习中的一个笔记,以备后期翻阅。

Shell能干什么

学习一项知识,凭的是兴趣,这是一个理由;另一个理由则是为了工作。好吧,我高尚一回,我觉对不是为了生计而去学习Shell脚本,纯粹是为了兴趣,弥补我大学时期没有学习Shell脚本而留下来的遗憾。而更多的人学习Shell并不是和我一样,更多的是为了工作,解决工作中的实际问题而决定要看看Shell脚本的,那么Shell脚本在工作中到底能干什么呢?先看看以下问题:

  1. 你是否经常需要处理一些重复性的工作?
  2. 你是否经常发现使用高级语言,如C++去处理一些事情发现大材小用?
  3. 你工作中是否经常需要进行一些批量处理的任务?
  4. ......

如果对于上面的问题,如果你回答“YES”。那你就非常有必要去学习一下Linux Shell脚本。好了,想必你已经决定了去看看Shell了。来吧。

一段简单的Shell

首先来一段简单的Shell脚本,整体上对Shell有一个简单的认识。

#!/bin/bash

cd ~ # 切换到用户的主目录,也就是/home/xxx
mkdir shell_test # 创建一个名为shell_test的文件夹

for ((i=0; i<10; i++)) # Shell的for循环
do
    touch test_$i.txt #创建空文件,文件名为test_0.txt, test_1.txt ...
done

上面是一段简单的Shell程序,实现在功能为:

  1. 在用户主目录下创建一个shell_test文件夹;
  2. 在用户主目录下创建10个规定命名格式的空文件。

由于是第一个Shell程序,所以有必要逐行解释一下,留下一个好的印象。

  • 第一行:指定脚本解释器,这里是用/bin/bash做解释器;
  • 第二行:切换到当前用户的home目录;
  • 第三行:创建一个名为shell_test的空目录;
  • 第四、五行:for循环,一共循环10次;
  • 第六行:创建10个名称为test_0.txt, test_1.txt格式的空文件。

cdmkdirtouch都是系统自带的程序,一般在/bin目录下;而fordodone都是Shell的关键字。
Shell中使用#开头的行就是注释。
一个简单的程序之后,我们就开始进入Shell的语法学习吧。

变量

从变量开始学习这段旅程。

基础知识

  1. 在Shell中,使用变量之前不需要事先声明,只是通过使用它们来创建它们;
  2. 在默认情况下,所有变量都被看做是字符串,并以字符串来存储;
  3. Shell变量是区分大小写的;
  4. 在Shell中,通过在变量名前加一个$符号来访问它的内容,无论何时想要获取变量内容,都必须在它前面加一个$符号;

下面通过一段Shell脚本来详细的说明上面的内容:

#!/bin/bash

var1=10 #定义一个变量var1

#定义一个变量var2,对于字符串中有空格的情况,需要使用引号将字符串括起来,
#此外等号两边不能有空格
var2="Jelly Think"

echo $var1 #获取变量var1的值
echo $var2 #获取变量var2的值

使用read
在Shell中,我们可以使用read命令将用户的输入赋值给一个变量。这个命令需要一个参数,即准备读入用户输入数据的变量名,然后它会等待用户输入数据。通常情况下,在用户按下回车键时,read命令结束。例如以下代码:

#!/bin/bash

read var1 #读入用户输入的var1变量的值
echo $var1 #输出var1的值

exit 0

引号的使用技巧
在上面的代码中也说了,如果字符串中包含了空格,就需要使用引号将字符串括起来,而这只是引号的一个简单的使用。
像$var1这种的变量在引号中的行为取决于你所使用的引号类型。这句话有以下两层意思:

  1. 如果把一个$变量表达式放在双引号中,程序执行到这一行时就会把变量替换为它的值;
  2. 如果把一个$变量表达式放在单引号中,就不会发生替换现象;

但是,我们可以通过在$字符前面加上一个\字符取消它的特殊含义,也就是经常说的转义字符。下面通过一段简单的代码来理解上面内容的意思:

#!/bin/bash

var1="JellyThink"

echo "This is $var1" #输出:This is JellyThink
echo 'This is $var1' #输出:This is $var1
echo "This is \$var1" #输出:This is $var1

exit 0

环境变量
当一个Shell脚本程序开始执行时,一些变量根据环境设置中的值进行初始化,一般比较常用的有以下几个:

  • $HOME:当前用户的主目录,例如:/home/jelly
  • $PATH:以冒号分隔的用来搜索命令的目录列表;
  • $0:Shell脚本的名字;
  • $#:传递给脚本的参数个数;
  • $$:Shell脚本的进程号,脚本程序通常会用它来生成一个唯一的临时文件。

参数变量
如果脚本程序在调用时带有参数,一些额外的变量就会被创建。即使没有传递任何参数,环境变量$#也依然存在,只不过它的值是0罢了。例如以下实力代码:

#!/bin/bash

#参数的命名是$1、$2......
#$0表示脚本的名字

#输出参数个数
echo "参数个数为:$#"
echo "脚本名字:$0"
echo "第一个参数:$1"
echo "第二个参数:$2"

exit 0

输出如下:

参数个数为:2
脚本名字:./argsDemo.sh
第一个参数:Jelly
第二个参数:Think

条件判断

我们知道,所有程序设计语言的基础是对条件进行测试判断,并根据测试结果采取不同行动的能力。在总结之前,先看看Shell脚本程序里可以使用的条件结构,然后再来看看使用这些条件的控制结构。

一个Shell脚本能够对任何可以从命令行上调用的命令的退出码进行判断,这其中也包括我们写的Shell脚本程序。这就是为什么要在所有自己编写的脚本程序的结尾包括一条返回值的exit命令的重要原因。

test或[命令
在实际工作中,大多数脚本程序都会广泛使用Shell的布尔判断命令[test。在一些系统上,这两个命令其实是一样的,只是为了增强可读性,当使用[命令时,我们还使用符号]来结尾。写了这么多程序了,还是头一次见,将一个[作为一个命令。算我孤陋寡闻了。下面就通过一个简单的例子来看看test[是如何使用的。

#!/bin/bash

if test -f testDemo.sh
then
    echo "testDemo.sh exists."
fi

if [ -f test.c ]
then
    echo "test.c exists."
else
    echo "I cannot find exists."
fi

exit 0

我们通过使用-f来判断指定文件是否存在。test命令可以使用的条件类型可以归为3类:

  • 字符串比较;
  • 算术比较;
  • 文件相关的条件测试。

下面就分别看看。

字符串比较 结果
string1 = string2 如果两个字符串相同,结果就为真
string1 != string2 如果两个字符串不同,结果就为真
-n string 如果字符串不为空,则结果为真
-z string 如果字符串为一个空串(null),则结果为真
算术比较 结果
expression1 -eq expression2 如果两个表达式相等,则结果为真
expression1 -ne expression2 如果两个表达式不等,则结果为真
expression1 -gt expression2 如果expression1大于expression2,则为真
expression1 -ge expression2 如果expression1大于等于expression2,则为真
expression1 -lt expression2 如果expression1小于expression2,则为真
expression1 -le expression2 如果expression1小于等于expression2,则为真
!expression 表达式为假,则结果就为真;反之亦然
文件条件测试 结果
-d file 如果文件是一个目录,则为真
-f file 如果文件是一个普通文件,则为真;也可以用来测试文件是否存在
-r file 如果文件可读,则结果为真
-s file 如果文件大小不为0,则结果为真
-w file 如果文件可写,则结果为真
-x file 如果文件可执行,则结果为真

控制结构

Shell也有一组控制结构,它们与其它程序语言中的控制接口很相似,下面就分开来总结它们。

if语句
结构如下:

if condition
then
    statements
else
    statements
fi

代码示例:

#!/bin/bash

var1=Jelly #这个是赋值,不能有空格分隔
var2=Think

if [ $var1 = $var2 ] #‘=’号两边都需要空格分隔
then
    echo "$var1 = $var2"
else
    echo "$var1 != $var2"
fi

exit 0

elif语句
结构如下

if condition
then
    statements
elif condition
    statements
else
    statements
fi

一个很容易出错的问题。例如以下代码:

#!/bin/bash

echo "Is it morning? please answer yes or no."
read timeofday

if [ $timeofday = "yes" ]
then
    echo "Good morning."
elif [ $timeofday = "no" ]
then
    echo "Good afternoon."
else
    echo "Sorry, $timeofday not recognized. Enter yes or no."
    exit 1
fi

exit 0

上面这段代码很简单,运行以下,如果你不输入yesno,就会运行出错,得到以下提示信息:

./elifDemo1.sh: line 6: [: =: unary operator expected
./elifDemo1.sh: line 9: [: =: unary operator expected

这是为何?代码中有if [ $timeofday = "yes" ],当我不输入任何内容时,这个if语句就会变成这样if [ = "yes" ],很明显,这不是一个合法的条件。为了避免出现这种情况,我们必须给变量加上引号,改成这样if [ "$timeofday" = "yes" ]。这样就没有问题了。

for语句
结构如下:

for variable in values
do
    statements
done

代码示例:

#!/bin/bash

for foo in Jelly Think Website
do
    echo $foo
done

exit 0

在文章的开头,那段简单的代码中,也包含了for的简单使用。

while语句
结构如下:

while condition
do
    statements
done

代码示例:

#!/bin/bash

echo "Enter password: "
read pwd

while [ "$pwd" != "root" ]
do
    echo "Sorry, try again."
    read pwd
done

exit 0

until语句
结构如下:

until condition
do
    statements
done

它与while循环很相似,只是把条件测试反过来了;也就是说,循环将反复执行直到条件为真。

case语句
结构如下:

case variable in
    pattern [ | pattern] ...) statements;;
    pattern [ | pattern] ...) statements;;
    ...
esac

case的代码结构相对来说是比较复杂的。case结构具备匹配多个模式,然后执行多条相关语句的能力,这使得它非常适合于处理用户的输入。下面通过一个实例来看看case的具体使用。

#!/bin/bash

echo "Is it morning? Please answer yes or no."
read input

case "$input" in
    yes ) echo "Good Morning.";;
    no ) echo "Good Afternoon.";;
    y ) echo "Good Morning.";;
    n ) echo "Good Afternoon.";;
    * ) echo "Sorry, answer not recognized";;
esac

exit 0

case语句被执行时,它会把变量input的内容与各字符串依次进行比较。一旦某个字符串与输入匹配成功,case命令就会执行紧随右括号)后面的代码,然后就结束。
在代码中,最后面的*表示匹配任何字符串,我们在写代码时,总是在其它匹配之后再添加一个*以确保如果没有字符串得到匹配,case语句也会执行某个默认动作。
由于case比较复杂,所以不得不再来一段代码,究其用法,如下:

#!/bin/bash

echo "Is it morning? Please answer yes or no."
read input

case "$input" in
    yes | y | Yes | YES ) echo "Good Morning.";;
    n* | N* ) echo "Good Afternoon.";;
    * ) echo "Sorry, answer not recognized.";;
esac

exit 0

上面这段代码,使用了|符号,也就是说,也就是合并了多个匹配模式;同时还使用了*通配符;没有问题,上面的代码运行的很好。

&&和||操作符
Shell中也支持&&||符号,和C++语言中的是一样;比如:

statement1 && statement2 && statement3 && ...

从左开始顺序执行每条命令,如果一条命令返回的是true,它右边的下一条命令才能执行。如果此持续直到有一条命令返回false,或者列表中的所有命令都执行完毕;遵循“短路”规则。

statement1 || statement2 || statement3 || ...

从左开始顺序执行每条命令,如果一条命令返回的是false,它右边的下一条命令才能够被执行。如此持续直到有一条命令返回true,或者列表中的所有命令都执行完毕。

语句块
在Shell中也有语句块,使用{}来定义一个语句块。我们可以把多条语句放到一个语句块中执行。

函数
函数,这么NB的东西,Shell怎么能少呢。定义函数的结构如下:

function_name()
{
    statements
}

代码示例:

#!/bin/bash

foo #运行到这里,还没有定义foo函数,会报错

foo() {
    echo "Function foo is executing."
}

echo "script starting"
foo #输出"Function foo is executing."
echo "script ended"

exit 0

脚本程序从自己的顶部开始执行,当它遇到了foo() {结构时,它知道脚本正在定义一个名为foo的函数。当执行到单独的foo时,Shell就知道应该去执行刚才定义的函数了。函数执行完毕以后,脚本接着foo后的代码继续执行。
当一个函数被调用时,脚本程序的位置参数($*$@$#$1$2等)会被替换为函数的参数,这也是我们读取传递给函数的参数的方法。当函数执行完毕后,这些参数会恢复为它们先前的值。
我们可以使用local关键字在Shell函数中声明局部变量,局部变量将仅在函数的作用范围内有效。此外,函数可以访问全局作用范围内的其它Shell变量。如果一个局部变量和一个全局变量的名字相同,前者就会覆盖后者,但仅限于函数的作用范围之内,例如以下代码:

#!/bin/bash

sample_text="global variable"

foo()
{
    local sample_text="local variable"
    echo "Function foo is executing..."
    echo $sample_text
}

echo "script starting..."
echo $sample_text

foo

echo "script ended..."
echo $sample_text

exit 0

输出如下:

script starting...
global variable
Function foo is executing...
local variable
script ended...
global variable

总结

终于总结完第一部分了,还有第二部分,在下一篇博文中将主要总结Shell中经常使用的一些命令。这篇对Shell中的一些基础进行总结的博文就到此了,下一篇再见。

果冻想-一个原创技术文章分享网站。

2014年10月28日 于深圳。

如果你觉的文章还不错,可以关注果冻想微信公众号,定期推送技术文章:

原文地址:https://www.cnblogs.com/vipygd/p/8570767.html

时间: 2024-10-09 20:20:27

Linux Shell简明教程(一)的相关文章

Linux Shell系列教程之(七)Shell输出

本文是Linux Shell系列教程的第(七)篇,更多shell教程请看:Linux Shell系列教程 与其他语言一样,Shell中也有输出操作,而且在实际应用中也是非常重要的,今天就为大家介绍下Shell输出操作. Shell echo命令 echo命令是Shell的一个内部指令,用于在屏幕上打印出指定的字符串. 命令格式: echo arg 转义字符 像其他高级语言一样,Shell也使用反斜杠“\”作为转义字符. 例子: echo "\"It is a test\"&q

Linux Shell系列教程之(六)Shell数组

本文是Linux Shell系列教程的第(六)篇,更多shell教程请看:Linux Shell系列教程 Shell在编程方面非常强大,其数组功能也非常的完善,今天就为大家介绍下Shell数组的用法. Shell支持一维数组(不支持多维数组),并且没有限定数组的大小. 类似与C语言,数组元素的下标由0开始编号.获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0. 一.Shell数组的定义 在Shell中,用括号来表示数组,数组元素之间用“空格”分割开. 定义数组的一般形式

Linux Shell系列教程之(四)Shell注释

本文是Linux Shell系列教程的第(四)篇,更多shell教程请看:Linux Shell系列教程 与许多的编程语言一样,Shell中也有注释符号,今天就为大家来介绍下Shell中的注释的语法及用法. Shell中的注释以“#”号开头,所有以“#”号开头的代码都会被解释器所忽略. 比如下面的代码: #!/bin/bash # Author : linuxdaxue.com # Date : 2016-05-15 echo "What is your name?" read PER

Linux Shell系列教程之(三)Shell变量

本文是Linux Shell系列教程的第(三)篇,更多shell教程请看:Linux Shell系列教程 Shell作为一种高级的脚本类语言,也是支持自定义变量的.今天就为大家介绍下Shell中的变量相关知识. 为使Shell编程更有效,系统提供了一些Shell变量.Shell变量可以保存诸如路径名.文件名或者一个数字这样的变量名. Shell将其中任何设置都看做文本字符串.有两种变量,本地和环境.严格地说可以有 4种,但其余两种是只读的,可以认为是特殊变量,它用于向Shell脚本传递参数. 定

Linux Shell脚本教程

v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);} Normal 0 false 7.8 磅 0 2 false false false EN-US ZH-CN X-NONE /* Style Definitions */ table.MsoNormalTable {

Linux Shell系列教程之(八)Shell printf命令详解

本文是Linux Shell系列教程的第(八)篇,更多shell教程请看:Linux Shell系列教程 在上一篇:Linux Shell系列教程之(七)Shell输出这篇文章中,已经对Shell printf命令有了一个简略的介绍,本篇给大家详细介绍下Shell中的printf命令. 一.Shell printf命令语法 printf format-string [arguments...] format-string为描述格式规格的字符串,用来描述输出的排列方式,最好为此字符串加上引号.此字

Linux Shell系列教程之(十七) Shell文件包含

本文是Linux Shell系列教程的第(十七)篇,更多Linux Shell教程请看:Linux Shell系列教程 通过文件包含,可以引用其他文件的内容,也可以将复杂内容分开,使程序结构更加清晰. 所以高级语言都支持文件包含或者包的引用,Shell当然也支持,接下来就为大家介绍下Shell文件包含的相关知识. 一.Shell文件包含格式 Shell文件包含的格式如下,使用点号“.”+文件名包含: . filename 或者source+文件名: source filename 二.Shell

Linux Shell系列教程之(十六) Shell输入输出重定向

本文是Linux Shell系列教程的第(十六)篇,更多Linux Shell教程请看:Linux Shell系列教程 Shell中的输出和输入的重定向是在使用中经常用到的一个功能,非常实用,今天就为大家介绍下Shell输入输出重定向的相关知识. 一.Shell输入输出重定向概述 在了解重定向相关知识之前,我们先来看看Linux的文件描述符. Linux的文件描述符可以理解为linux跟踪打开文件,而分配的一个数字,这个数字有点类似c语言操作文件时候的句柄,通过句柄就可以实现文件的读写操作. 用

Linux Shell系列教程之(十)Shell for循环

本文是Linux Shell系列教程的第(十)篇,更多Linux Shell教程请看:Linux Shell系列教程 基本任何语言都有自己的循环语句,Shell当然也不例外,今天就为大家介绍下Shell for循环的用法. Shell for循环语法 Shell for循环的语法如下所示 for 变量 in 列表 do command1 command2 ... commandN done 列表是一组值(数字.字符串等)组成的序列,每个值通过空格分隔.每循环一次,就将列表中的值依序放入指定的变量