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 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脚本编制的理论和概念。 我将在以后发布有关特定技术或如何解决特定问题的更详细的教程。
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 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
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
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
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:如果command
和anothercommand
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
(零),如果至少一个command
和anothercommand
执行并返回0
。
command || anothercommand
NOT: invert the logic return value of command
:
NOT:反转command
的逻辑返回值:
! command
In you can use several control structures which you might be familiar with:
您可以使用几种您可能熟悉的控制结构:
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.
注意括号吗? 当我们必须对布尔表达式进行任何形式的评估时,必须添加方括号。
While condition
resolves to a true value, run command
当condition
解析为真值时,运行command
while condition
do
command
done
Until condition
resolves to a true value, run command
在condition
解析为真值之前,运行command
until condition
do
command
done
Iterate a list and execute a command for each item
遍历列表并为每个项目执行命令
for item in list
do
command
done
Inside the loops, you can use the break
and continue
statements to break the loop completely, or just skip the current iteration.
在循环内部,您可以使用break
和continue
语句完全中断循环,或者仅跳过当前迭代。
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
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"
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
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
进行检查。
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.
如果我们接受选项a
和b
,则将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.
现在,如果您错过添加参数的操作,错误消息将有所不同。
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
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
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"
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[@]}
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
。
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"
shell bash脚本