Bash Shell脚本的介绍

151 阅读5分钟

Shell脚本是一种强大的方式,可以将你经常在电脑上执行的任务自动化。

在本教程中,我对shell脚本进行了广泛的概述,并将作为创建实用shell脚本的更深入和高级教程的基础参考。

请看我的Bash介绍帖子。

Bash给了你一组命令,这些命令放在一起可以用来创建小程序,按照惯例我们称之为脚本。

注意其中的区别。我们不说Bash编程,而是说Bash脚本,我们也不把Bash脚本称为 "Bash程序"。这是因为一般来说,你可以在达到一定的复杂程度后,就会觉得你的脚本变得不可收拾了。

但是Bash脚本之所以伟大,是因为除了Bash之外,你不需要其他任何东西来运行它们。没有编译器,没有解释器,只有你的shell。

在Perl、JavaScript或Python等编程语言中,有很多东西是你会错过的。

例如,变量没有范围,它们都是全局的,没有标准库,你没有模块系统。但它的优点是相当大的:你可以非常容易地调用任何CLI工具,就像你在shell中一样,而且Unix的方法是有许多小的实用命令,这确实使shell脚本大放异彩。用wget 执行网络请求,用awk 处理文本,以及更多。

Shell脚本是你最好了解的工具之一,至少知道当你看到一个程序时如何阅读它,以及它在你日常工作中能带来的好处。

本教程指导你了解Bash脚本的理论和概念。我将在未来发布关于具体技术或如何解决具体问题的更详细的教程。

基础知识

脚本被存储在文件中。你可以给一个shell脚本起任何名字和扩展名,这并不重要。重要的是,它必须在第一行以 "shebang "开头。

而且它必须是一个可执行的文件。

使用chmod ,一个实用的命令将一个文件设置为可执行文件。

你可以像这样使用它。

来使myscript 文件对你的用户来说是可执行的(我不打算在这里讨论权限的问题,但我很快就会讨论)。

现在,如果你在同一个文件夹中,你可以通过调用./myscript ,或者使用它的完整路径来执行这个脚本。

在学习的时候,我鼓励你--在可能的情况下--使用像这样的在线游乐场,它使事情更容易测试。

注释是编写程序时最重要的东西之一。以# 符号开头的行是一个注释(你在上面看到的shebang行除外)。

#!/bin/bash
# this is a comment

注释也可以从行尾开始。

#!/bin/bash
echo ok # this is a comment

变量

你可以通过使用= 操作符来设置变量。

例子。

ROOM_NUMBER=237
name=Flavio
nickname="Flavio"

你可以通过使用echo 内置命令并在 var 名称前加一个$ 来打印一个变量。

echo $ROOM_NUMBER
echo $name

操作符

Bash实现了一些编程语言中常用的算术运算符。

  • +
  • - 减法
  • * 乘法
  • / 除法
  • % 模数(除法的剩余部分)
  • ** 指数化

你可以用以下方式比较数值

  • <
  • <=
  • ==
  • >=
  • >

你也可以使用这些比较运算符。

  • -lt 小于
  • -gt 大于
  • -le 低于或等于
  • -ge 大于或等于
  • -eq 等于
  • -ne 不等于

以这种方式。

#!/bin/bash
age=23
minimum=18
if test $age -lt $minimum
then
  echo "Not old enough"
fi

逻辑运算符。

  • && 逻辑AND
  • || 逻辑OR

这些快捷方式允许进行算术运算,然后进行赋值。

  • +=
  • -=
  • *=
  • /=
  • %=

还有一些运算符,但这些是最常见的。

打印到屏幕上

你可以使用echo 命令将任何东西打印到屏幕上。

#!/bin/bash
echo "test"
echo test
echo testing something

逻辑条件

AND:如果commandanothercommand 同时执行并返回0 ,则评估为0 (零)。在shell命令中返回0意味着该命令是成功的。错误信息由一个非零的返回值来标识。

command && anothercommand

OR:如果commandanothercommand 中至少有一个执行并返回0 ,则评估为0 (零)。

command || anothercommand

NOT:反转command 的逻辑返回值。

控制结构

在你可以使用几个你可能熟悉的控制结构。

If/else 语句

简单的if

if condition
then
  command
fi

if then 。else

if condition
then
  command
else
  anothercommand
fi

嵌套if - then -else

if condition
then
  command
elif
  anothercommand
else
  yetanothercommand
fi

你可以通过使用分号将else 保持在同一行。

if condition ; then
  command
fi

例子。

#!/bin/bash
DOGNAME=Roger
if [ "$DOGNAME" == "" ]; then
  echo "Not a valid dog name!"
else
  echo "Your dog name is $DOGNAME"
fi

注意到大括号了吗?当我们要对一个布尔表达式进行任何形式的评估时,我们必须添加括号。

循环

While 循环

condition 解决为真值时,运行command

while condition
do
  command
done

直到

直到condition 解决为真值,运行command

until condition
do
  command
done

For in

遍历一个列表并为每项执行一个命令

for item in list
do
  command
done

断开并继续

在循环内部,你可以使用breakcontinue 语句来完全中断循环,或者只是跳过当前的迭代。

案例

一个案例控制结构可以让你根据一个值来选择不同的路线。

case value in
  a)
    command
    #...
    ;;
  b)
    command
    #...
    ;;
esac

fi 一样,esac 结束了case结构,你可以注意到它是case 的倒拼。

我们在每个案例后面加一个双分号。

一个*) 案例将处理所有没有明确表达的情况。使用一个| 符号,你可以表达一个案例的多个选择。

例子。

#!/bin/bash
read -p "How many shoes do you have?" value
case $value in
  0|1)
    echo "Not enough shoes! You can't walk"
    ;;
  2)
    echo "Awesome! Go walk!"
    #...
    ;;
  *)
    echo "You got more shoes than you need"
    #...
    ;;
esac

选择

一个select 结构向用户显示一个选择菜单,供其选择。

select item in list
do
  command
done

例子。

#!/bin/bash
select breed in husky setter "border collie" chiwawa STOP
do
  if [ "$breed" == "" ]; then
    echo Please choose one;
  else
    break
  fi
done

echo "You chose $breed"

测试条件

我在上面的控制结构中使用了condition 这个词。

你可以使用test Bash内置命令来检测条件,并返回一个真值(0)或假值(不是0)。

下面是一个例子。

#!/bin/bash
if test "apples" == "apples"
then
  echo Apples are apples
fi

if ! test "apples" == "oranges"
then
  echo Apples are not oranges
fi

读取来自命令行的输入

你可以通过使用read 内置命令使你的脚本具有交互性。这个命令从标准输入中读取一行,它可以以一种非常灵活的方式来格式化输入。

最简单的用法是。

这将打印 "年龄:",你可以输入一个数字,按回车键,这个数字将被分配给age

read-p 选项提供了一个内置的提示,并将输入的内容放在age 变量中。

read 命令还有很多选项,你可以通过在Bash中输入help read 来检查。

添加选项

选项是用连字符后的字母来指定的,像这样。

在你的代码中,你使用内置的命令getopts 来解析选项并获得值。

如果我们接受选项ab ,我们将getopts ab 送入一个while循环。

如果选项b 接受一个值,我们在它后面附加一个冒号: ,所以我们的getopts 调用格式是这样的。getopts ab: arg

下面是一个片段。

while getopts xy: arg
do
  case $arg in
    x) echo "Option $arg enabled" ;;
    y) echo "The value of $arg is $OPTARG" ;;
    esac
done

在这个脚本中,$OPTARG 被自动指定为选项字母。我们告诉getopts 我们接受哪些选项,并分别处理每一种情况。

错误是由getopts 自动处理的。我们可以选择自己处理错误信息,方法是在参数定义前加一个冒号:getopts :xy: arg

然后我们还要处理\?: 的情况。当我们传递一个无效的选项时,第一个被调用,当我们错过一个选项时,第二个被调用。

while getopts :xy: arg
do
  case $arg in
    x) echo "Option $arg enabled" ;;
    y) echo "The value of $arg is $OPTARG" ;;
    :) echo "$0: Must supply an argument to -$OPTARG." >&2
       exit 1 ;;
    \?) echo "Invalid option -$OPTARG ignored." >&2 ;;
    esac
done

现在,如果你错过了添加一个参数,错误信息是不同的。

使用参数的工作

在一个脚本中,你可以访问在调用时传递的任何参数。你可以使用$0,$1,$2 等等来访问它们,取决于位置,其中$0 是命令的名称,递增的数字是参数位置的递增。在位置9之后,你需要使用大括号。${10},${11}...

例如,运行这个startCar 脚本。

#!/bin/bash
echo $0
echo $1

as./startCar fiesta 将打印

特殊的$* 语法会打印出所有的参数,而$# 则会打印出所传递的参数的数量。

./test.sh Milan Florence Rome
3 Milan Florence Rome

将选项与参数分开

如果你同时有选项和参数,你需要把它们分开。你可以用连字符来做这个。

driveCar -m "Ford Fiesta" - Milan Florence Rome

处理字符串

给定一个字符串。

你可以用以下方法得到它的长度${#dogname}

在处理字符串时,一定要在其周围使用引号,以避免Bash解释其中的特殊字符。

你可以用=== 操作符来比较两个字符串,这是一样的。

"$dogname" = "$anotherdogname"
"$dogname" == "$anotherdogname"

这不是一个赋值,因为= 的周围有空格。

你也可以检查不平等。

"$dogname" != "$anotherdogname"

数组

数组是一个项目的列表,在圆括号内声明。

breeds=(husky setter "border collie" chiwawa)

你可以用方括号引用数组中的任何项目。

而且你可以用这个特殊的语法来获得项目的总数。

内置命令

到目前为止,你已经看到了一些内置命令,比如这些。

  • test
  • read
  • echo

Bash有很多这样的命令。你可以通过调用help 来查看它们,然后你可以使用例如help read 来找到每个命令的帮助。

功能

就像在JavaScript或其他编程语言中一样, 你可以创建一些可重复使用的代码, 给它们取个名字, 然后在需要时调用它们.

Bash称它们为函数

你可以用以下方式定义一个函数

例子。

来定义一个函数,然后像这样调用它。

你可以将参数传递给文件夹,而不需要声明它们--你只需将它们作为$1,$2 等来引用。就像你对脚本参数所做的那样。

function cleanFolder {
  echo "Clean folder $1"
}
cleanFolder "/Users/flavio/Desktop"