shell bash脚本_Bash Shell脚本介绍

凌黎明
2023-12-01

shell bash脚本

Shell scripting is an powerful way to automate tasks that you regularly execute on your computer.

Shell脚本是一种自动执行通常在计算机上执行的任务的强大方法。

In this tutorial I give an extensive overview of shell scripting, and will be the base reference for more in-depth and advanced tutorials on creating practical shell scripts.

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

Check out my introduction to Bash post.

查看我对Bash帖子的介绍

Bash gives you a set of commands that put together can be used to create little programs, that by convention we call scripts.

Bash为您提供了一组命令,这些命令可以一起用来创建小程序,按照惯例,我们将其称为脚本。

Note the difference. We don’t say Bash programming but Bash scripting, and we don’t call Bash scripts “Bash programs”. This is because you can generally reach a certain amount of complexity before feeling that your scripts gets out of hand.

注意区别。 我们不是说Bash编程,而是说Bash脚本,我们也没有将Bash脚本称为“ Bash程序”。 这是因为在感觉脚本失控之前,通常可以达到一定程度的复杂性。

But Bash scripts are great because you don’t need anything else than Bash to run them. No compiler, no interpreter, just your shell.

但是Bash脚本很棒,因为您只需要Bash即可运行它们。 没有编译器,没有解释器,只有您的shell。

There are many things that you’ll miss from programming languages like Perl or JavaScript or Python.

Perl或JavaScript或Python等编程语言会遗漏许多东西。

Variables have no scope, they are all global, there is no standard library, you don’t have a module system, for instance. But the advantages are pretty great: you can very easily invoke any CLI tool just like you were in the shell, and the Unix approach of having many little utility commands really makes shell scripting shine. Perform network requests with wget, process text using awk, and more.

变量没有作用域,它们都是全局的,没有标准库,例如,您没有模块系统。 但是优点非常棒:您可以像在shell中一样轻松地调用任何CLI工具,而Unix方法具有许多小的实用程序命令确实使shell脚本大放异彩。 使用wget执行网络请求,使用awk处理文本等。

Shell scripting is one of the tools you’d better know, at least know how to read a program when you see it, and the goodies it can bring in your day to day work.

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

This tutorial guides you to the theory and concepts of Bash scripting. I will post more detailed tutorials on specific techniques or how to solve specific problems in the future.

本教程将引导您了解Bash脚本编制的理论和概念。 我将在以后发布有关特定技术或如何解决特定问题的更详细的教程。

基本 (Basics)

Scripts are stored in files. You can give any name and extension to a shell script, it does not matter. The important thing is that it must start with a “shebang” on the first line:

脚本存储在文件中。 您可以为shell脚本指定任何名称和扩展名,这没关系。 重要的是,它必须在第一行以“ shebang”开头:

#!/bin/bash

and it must be an executable file.

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

A file is set as executable using chmod, an utility command.

使用实用程序命令chmod将文件设置为可执行文件。

You can use it like this:

您可以像这样使用它:

chmod u+x myscript

to make the myscript file executable for your user (I’m not going in the permissions rabbit hole here, but I will cover them soon).

以使myscript文件可为您的用户执行(我不在这里的权限兔子洞中,但我会尽快对其进行介绍)。

Now you can execute the script if you are in the same folder by calling it ./myscript, or using the full path to it.

现在,如果您位于同一文件夹中,可以通过调用./myscript或使用其完整路径来执行脚本。

While learning I encourage you - when possible - to use an online playground like this one, it makes things easier to test.

虽然学习我鼓励你-在可能的情况-使用在线操场像这样的 ,它使事情更容易测试。

注释 (Comments)

Comments are one of the most important things when writing programs. A line starting with the # symbol is a comment (with the exception of the shebang line you saw above here).

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

#!/bin/bash
# this is a comment

A comment can start at the end of a line too:

评论也可以从行尾开始:

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

变数 (Variables)

You can set variables by using the = operator:

您可以使用=运算符设置变量:

name=value

Examples:

例子:

ROOM_NUMBER=237
name=Flavio
nickname="Flavio"

You can print a variable by using the echo built-in command and prepending a $ to the var name:

您可以使用echo内置命令并在变量名前加$来打印变量:

echo $ROOM_NUMBER
echo $name

经营者 (Operators)

Bash implements some arithmetic operators commonly used across programming languages:

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

  • + add

    +添加

  • - subtract

    -减去

  • * multiply

    *相乘

  • / divide

    /

  • % modulo (remainder of the division)

    模数% (除法余数)

  • ** exponentiation

    **求幂

You can compare values using

您可以使用

  • <

    <

  • <=

    <=

  • ==

    ==

  • >=

    >=

  • >

    >

You can also use these comparison operators:

您还可以使用以下比较运算符:

  • -lt lower than

    -lt低于

  • -gt greater than

    -gt大于

  • -le lower or equal than

    -le小于或等于

  • -ge greater or equal than

    -ge大于或等于

  • -eq equal to

    -eq等于

  • -ne not equal to

    -ne不等于

In this way:

通过这种方式:

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

Logical operators:

逻辑运算符:

  • && logical AND

    &&逻辑与

  • || logical OR

    || 逻辑或

These shortcuts allow to perform an arithmetic operation and then an assignment:

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

  • +=

    +=

  • -=

    -=

  • *=

    *=

  • /=

    /=

  • %=

    %=

There are some more operators, but those are the most common ones.

还有更多的运算符,但是那些是最常见的。

You can print anything to the screen using the echo command:

您可以使用echo命令在屏幕上打印任何内容:

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

逻辑条件 (Logical conditions)

AND: evaluates to 0 (zero) if both command and anothercommand execute and return 0. Returning zero in shell commands means the command was successful. An error message is identified by a non-zero return value.

AND:如果commandanothercommand command都执行并返回0则求值为0 (零)。 在shell命令中返回零表示该命令成功。 错误消息由非零返回值标识。

command && anothercommand

OR: evaluates to 0 (zero) if at least one of command and anothercommand execute and return 0.

OR:计算结果为0 (零),如果至少一个commandanothercommand执行并返回0

command || anothercommand

NOT: invert the logic return value of command:

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

! command

控制结构 (Control structures)

In you can use several control structures which you might be familiar with:

您可以使用几种您可能熟悉的控制结构:

如果/其他语句 (If/else statements)

Simple if:

if简单:

if condition
then
  command
fi

if then else:

if然后else

if condition
then
  command
else
  anothercommand
fi

Nested if - then - else:

if -然后- else嵌套:

if condition
then
  command
elif
  anothercommand
else
  yetanothercommand
fi

You can keep the else on the same line by using a semicolon:

您可以使用分号将else保持在同一行:

if condition ; then
  command
fi

Example:

例:

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

Notice the brackets? We must add brackets when we have to do any kind of evaluation of a boolean expression.

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

循环 (Loops)

While循环 (While loop)

While condition resolves to a true value, run command

condition解析为真值时,运行command

while condition
do
  command
done

直到 (Until)

Until condition resolves to a true value, run command

condition解析为真值之前,运行command

until condition
do
  command
done

对于 (For in)

Iterate a list and execute a command for each item

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

for item in list
do
  command
done

打破并继续 (Break and continue)

Inside the loops, you can use the break and continue statements to break the loop completely, or just skip the current iteration.

在循环内部,您可以使用breakcontinue语句完全中断循环,或者仅跳过当前迭代。

案件 (Case)

A case control structure lets you pick different routes depending on a value.

案例控制结构使您可以根据值选择不同的路由。

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

Like with fi, esac ends the case structure and as you can notice it’s case spelled backwards.

fi一样, esac结束了大小写结构,并且您可以注意到它的case是反向拼写的。

We add a double semicolon after each case.

在每种情况下,我们添加一个双分号。

A *) case would handle all the cases not explicitly expressed. Using a | symbol you can express multiple choices for a single case.

*)案例将处理所有未明确表述的案例。 使用| 符号,您可以为一个案例表达多种选择。

Example:

例:

#!/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)

A select structure shows the user a menu of choices to choose:

select结构向用户显示一个可供选择的菜单:

select item in list
do
  command
done

Example:

例:

#!/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"

测试条件 (Testing conditions)

I used the term condition in the above control structures.

我在上述控制结构中使用了condition一词。

You can use the test Bash built-in command to check for a condition and return a true (0) or false value (not 0).

您可以使用test Bash内置命令来检查条件,并返回true( 0 )或false值(非0 )。

Here is an example:

这是一个例子:

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

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

从命令行读取输入 (Reading input from the command line)

You can make your scripts interactive by using the read built-in command. This command reads a line from the standard input, and it can format input in a very flexible way.

您可以使用read内置命令使脚本具有交互性。 该命令从标准输入中读取一行,并且可以非常灵活地格式化输入。

The simplest usage is:

最简单的用法是:

echo "Age:"
read age

this is going to print “Age:” and you can enter a number, press enter and that number will be assigned to the age variable.

这将打印“ Age:”,您可以输入数字,按Enter键,该数字将分配给age变量。

The -p option of read provides a built-in prompt, and puts the input in the age variable:

read-p选项提供内置提示,并将输入内容放入age变量中:

read -p "Age: " age

The read command has many more options, which you can inspect by typing help read in Bash.

read命令具有更多选项,您可以通过在Bash中键入help read进行检查。

添加选项 (Adding options)

Options are specified using a hyphen followed by a letter, like this:

使用连字符和字母来指定选项,如下所示:

ls -a
driveCar -b "Ford"

In your code you use the built-in command getopts to parse the options and get the value.

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

If we accept options a and b , we feed getopts ab to a while loop.

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

If option b accepts a value, we append a colon : after it, so we format our getopts call like this: getopts ab: arg

如果选项b接受一个值,我们会在其后附加一个冒号: ,因此我们将格式化getopts调用的格式如下: getopts ab: arg

Here’s a snippet:

这是一个片段:

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

In this script, $OPTARG is automatically assigned the option letter. We tell getopts which options we accept, and we handle each case separately.

在此脚本中,自动$OPTARG分配了选项字母。 我们告诉getopts我们接受哪些选项,然后分别处理每种情况。

Errors are handled automatically by getopts. We can choose to handle error messages ourselves, by prepending a colon : before the arguments definition: getopts :xy: arg.

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

Then we also handle the \? and : cases. The first is called when we pass an invalid option, and the second is called when we miss an option:

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

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

Now if you miss to add an argument, the error messages are different.

现在,如果您错过添加参数的操作,错误消息将有所不同。

使用参数 (Working with parameters)

Inside a script you can access any parameter that was passed at invocation time. You access them using $0, $1, $2 and so on, depending on the position, where $0 is the name of the command and incrementing the number the position of the parameter is incremented. After position 9 you need curly braces: ${10}, ${11}

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

For example running this startCar script:

例如,运行以下startCar脚本:

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

as ./startCar fiesta will print

./startCar fiesta将打印

./startCar
fiesta

The special $* syntax prints all the parameters, and $# the number of parameters passed:

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

#!/bin/bash
echo $# $*
./test.sh Milan Florence Rome
3 Milan Florence Rome

将选项与参数分开 (Separating options from parameters)

If you have both options and parameters you need to separate them. You do this with a hyphen:

如果同时具有选项和参数,则需要将它们分开。 您可以使用连字符进行此操作:

driveCar -m "Ford Fiesta" - Milan Florence Rome

使用字符串 (Working with strings)

Given a string:

给定一个字符串:

dogname="Roger"

You can get its length using ${#dogname}

您可以使用${#dogname}来获取其长度

Always use quotes around strings, when working with them, to avoid Bash interpreting the special characters inside them.

与字符串一起使用时,请始终在字符串两边使用引号,以避免Bash解释其中的特殊字符。

You can compare 2 strings using the = or == operator, it’s the same:

您可以使用===运算符比较2个字符串,这是相同的:

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

It’s not an assignment because of the spaces surrounding the =.

由于=周围有空格,因此不是分配。

You can also check for unequality:

您还可以检查不平等情况:

"$dogname" != "$anotherdogname"

数组 (Arrays)

An array is a list of items, declared inside parentheses:

数组是在括号内声明的项目列表:

breeds=(husky setter "border collie" chiwawa)

You can reference any item inside an array using square brackets:

您可以使用方括号引用数组中的任何项目:

breeds[0]
breeds[1]

and you can get the total number of items using this special syntax:

您可以使用以下特殊语法获取商品总数:

${#breeds[@]}

内置命令 (Built-in commands)

So far you’ve seen a few built-in commands already, like these:

到目前为止,您已经看到了一些内置命令,例如:

  • test

    test

  • read

    read

  • echo

    echo

Bash has a number of them. You can see them all by calling help and then you can find the help for each command using for example help read.

Bash有很多。 您可以通过调用help来查看所有内容,然后使用例如help read来查找每个命令的help read

功能 (Functions)

Just like in JavaScript or in any other programming language, you can create little reusable pieces of code, give them a name, and call them when you need.

就像在JavaScript或任何其他编程语言中一样,您可以创建少量可重用的代码,给它们命名,并在需要时调用它们。

Bash calls them functions.

Bash将其称为函数

You define a function with

您定义一个函数

function name {

}

Example:

例:

function cleanFolder {

}

and you invoke it like this:

然后像这样调用它:

cleanFolder

You can pass parameter to folders, without the need of declaring them - you just reference them as $1, $2 etc. Like you do for script parameters:

您可以将参数传递到文件夹,而无需声明它们-您只需将它们引用为$1$2等。就像对脚本参数所做的那样:

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

翻译自: https://flaviocopes.com/bash-scripting/

shell bash脚本

 类似资料: