shell脚本技巧_功能强大的Shell脚本技巧

shell脚本技巧

by BinHong Lee

李彬宏

Shell脚本与python或Perl (Shell scripts vs python or Perl)

It's 2020 now, who writes shell scripts anymore? Am I right? Well, apparently I do. ¯\_(ツ)_/¯

现在是2020年,谁再编写Shell脚本? 我对吗? 好吧,显然我愿意。 ¯\ _(ツ)_ /¯

There are some good arguments for that here and here which mainly revolve around 2 things:

这里和这里有一些很好的论据,主要围绕两件事:

  1. Shell exists in all Unix systems and makes use of system default features.

    Shell在所有Unix系统中都存在,并使用系统默认功能。
  2. Shell is an “interactive command function” designed to get user inputs during the process of running them.

    Shell是一个“交互式命令功能”,旨在在运行用户输入的过程中获取用户输入。

Also, here’s an additional relevant reading about the differences between sh and bash.

另外, 这是有关shbash之间差异的其他相关读物。

争论 (Arguments)

In some occasions, you will need to pass an argument (or expect one) into the script like how you might pass a param into a function. In that case, you will use something like $1 for the first argument, $2 for the second. Here's an example of how it would look like:

在某些情况下,您将需要像在参数中传递参数一样将一个参数(或期望一个参数)传递给脚本。 在这种情况下,第一个参数将使用$1 ,第二个参数将使用$2 。 这是一个看起来像的例子:

In script run_this.sh:

在脚本run_this.sh

echo "The input message was $1."

Running the command:

运行命令:

./run_this.sh userInputThe input message was userInput.

Note: The params are separated by spaces so if you want to input a string as a param that contains a space, it might need to be something like ./run_this.sh "user input" just so "user input" would be counted as $1 entirely.

注意:参数用空格分隔,因此,如果您想输入一个字符串作为包含空格的参数,则它可能需要像./run_this.sh "user input" ,这样"user input"将被计为完全是$1

In the occasion where you are not sure how long the user input might be and you want to capture it all, you would use $@ instead. In the following example, I took in the entire string and print it out word by word after breaking them into a string array according to the spaces in between.

如果您不确定用户输入可能需要多长时间,并且想要捕获所有输入,则可以使用$@代替。 在下面的示例中,我将整个字符串放入,并根据它们之间的间隔将它们分成字符串数组,然后逐字打印出来。

In script run_this.sh:

在脚本run_this.sh

userInputs=($@)for i in "${userInputs[@]}";; do  echo "$i"done

Running the command:

运行命令:

./run_this.sh who knows how long this can gowhoknowshowlongthiscango

功能 (Functions)

If you have done any sort of programming, you should be familiar with the concept of functions. It's basically a set of commands / operations that you will be repeating over and over again. Instead of repeating it multiple times in your code, you can put them into a function. Then just call the function which effectively reduces the lines of code that need to be written.

如果您完成了任何种类的编程,则应该熟悉函数的概念。 基本上,这是一组命令/操作,您将一遍又一遍地重复。 您可以将它们放入函数中,而不必在代码中重复多次。 然后,只需调用该函数即可有效减少需要编写的代码行。

Side note: If you don’t know already, LOC is a horrible metric for any sort of measurement in terms of programming. Don’t take this from me, take this from Bill Gates:

旁注:如果您还不了解,LOC是编程方面任何形式的度量的可怕指标。 不要从我这里拿走,从Bill Gates那里拿走:

“Measuring programming progress by lines of code is like measuring aircraft building progress by weight.”
“通过代码行来衡量编程进度就像通过重量来衡量飞机制造进度。”

Here’s how a normal function looks like:

正常功能的外观如下:

# Declaring the functiondoSomething() {
}
# Calling the functiondoSomething

Pretty straightforward and easy to understand. Now, here are a few differences between functions in shell scripts and a normal programming language.

非常简单易懂。 现在,这是Shell脚本中的功能与常规编程语言之间的一些区别。

参量 (Parameters)

If you were to pass a parameter / use a parameter into a function in Java, you have to declare them in the function declaration. They look something like this.

如果要向Java中的函数传递参数/使用参数,则必须在函数声明中声明它们。 他们看起来像这样。

public static void main(String[] args) {    doSomething("random String");}
private static void doSomething (String words) {    System.out.println(words);}

In the shell, however, they do not require a declaration of types or names at all. Each of them is like a separate script that lives in the script itself. If you were to use a param, just pass it in and call it like how you would do it if you were taking in input for this script at the top level. Something like this:

但是,在外壳程序中,它们根本不需要声明类型或名称。 它们每个都像一个单独的脚本,位于脚本本身中。 如果要使用参数,只需传入它,然后像调用顶级脚本中的输入一样调用它即可。 像这样:

doSomething() {    echo $1}
doSomething "random String"
  1. Similar to above, if you want to take in everything, you will use $@ instead of $1 since $1 would only use the first input (and $2 for the second etc.).

    与上述类似,如果您想接受所有内容,则将使用$@而不是$1因为$1仅使用第一个输入( $2用于第二个输入,等等)。

  2. Functions need to be declared ahead of where they are being called. (Usually beginning of the file before any main operations.)

    需要在调用函数之前声明函数。 (通常在执行任何主要操作之前从文件的开头开始。)

返回 (Return)

Let’s say we create a script like below named run_this.sh:

假设我们创建一个如下所示的脚本run_this.sh

doSomething() {    echo "magic"    return 0}
output=`doSomething`echo $output

Now let’s run it and see what is being assigned to the output variable.

现在运行它,看看分配给output变量的内容。

$ ./run_this.shmagic

Note that instead of 0, it shows magic instead. This is because when you do output=`doSomething`, it assigns the output message to output instead of the return value since the output message is how you communicate almost anything in the shell script.

请注意,它不是0而是显示magic 。 这是因为当您执行output=`doSomething` ,它将输出消息分配给output而不是返回值,因为输出消息是您在Shell脚本中交流几乎所有内容的方式。

So when does it make sense to use the return call? When you are using it as part of an if statement. Something like this:

所以,当它是有意义的使用return电话吗? 当您将其用作if语句的一部分时。 像这样:

In script run_this.sh:

在脚本run_this.sh

doSomething() {    echo "magic"    return 0}
if doSomething; then    echo "Its true!"fi

Running the command:

运行命令:

./run_this.shIts true!

In this case, return 0 means true while return 1 meant false in a traditional boolean sense.

在这种情况下,从传统的boolean意义上讲, return 0表示truereturn 1表示false

多行回声 (Multi-line echo)

There are times when you need to print a multi-line message. There are a few ways to go around this. The easiest way is to use echo multiple times like this:

有时您需要打印多行消息。 有几种解决方法。 最简单的方法是多次使用echo ,如下所示:

echo "line1"echo "line2"echo "line3"

It works but probably not the most elegant way to get around this. Instead, you can use cat <&lt; EOF instead. Something like this:

它有效,但可能不是解决此问题的最优雅的方法。 相反,您可以使用cat <&l t; 改为EOF。 像这样:

cat << EOFline1line2line3EOF

Note that there should not be anything (including spaces or tabs) before EOF. If you want to do it in an ifstatement, it should look something like this.

请注意, EOF之前不应有任何内容(包括空格或制表符)。 如果要在if语句中执行此操作,则它应类似于以下内容。

if [ "a" == "a" ]; then  cat << EOFline1line2line3EOFfi

Realize that even the messages themselves are aligned to the left. This is because if you leave them tabbed, the output message shown in the command line will also be tabbed. Also, if EOF is tabbed, the shell will complain about it and usually ends the script there.

请注意,即使消息本身也向左对齐。 这是因为如果您将它们置于选项卡中,则命令行中显示的输出消息也将被选项卡。 另外,如果将EOF为选项卡,则外壳程序将对其进行抱怨,并通常在此处结束脚本。

标志/选项 (Flags / Options)

You’ve probably seen some of the scripts or commands that comes with an ability to add flags (and sometimes arguments for the specific flag). Something like git commit -a -m "Some commit message".

您可能已经看到了一些脚本或命令,这些脚本或命令具有添加标志的功能(有时还可以添加特定标志的参数)。 像git commit -a -m "Some commit message"

Here’s a quick example of how it looks like (I’ve tried to be as comprehensive as possible with the example.)

这是一个简短的外观示例(我尝试对该示例进行尽可能全面的介绍。)

In script run_this.sh:

在脚本run_this.sh

while getopts ac: opt; do    case $opt in        a)            echo "\"a\" was executed."            ;;        c)            echo "\"c\" was executed with parameter \"$OPTARG\"."            ;;        \?)            echo "Invalid option: -$opt"            exit 1            ;;        :)            echo "option -$opt requires an argument."            exit 1            ;;    esacdone

Running the command:

运行命令:

./run_this.sh
./run_this.sh -a"a" was executed.
./run_this.sh -coption -c requires an argument.
./run_this.sh -c abcd"c" was executed with parameter "abcd".
./run_this.sh -a -c abc"a" was executed."c" was executed with parameter "abc".
./run_this.sh -xInvalid option: -x

In the above example, the differences between option -a and -c is that in the getopts line, c has a colon (:) following it after therefore telling the program to expect a parameter for the option. Another thing to keep in mind is that the options need to be declared in an alphabetical way. If you declare something like acb, the bdeclaration would be ignored, and using the -b flag would lead to the error message instead of the b case in the switch condition.

在上面的例子中,选项之间的差异-a-c是,在getopts线, c有冒号( :以下后它因此告诉程序期望的选项的参数)。 要记住的另一件事是,必须以字母顺序声明选项。 如果您声明类似acb ,则b声明将被忽略,并且在切换条件下使用-b标志将导致错误消息而不是b情况。

Thanks for reading!

谢谢阅读!

关于我 (About me)

I currently work at Facebook as a Software Engineer. I spend some of my free time experimenting and building new things with technologies I find fun and interesting. Follow my exploration journey here or on GitHub.

我目前在Facebook担任软件工程师。 我花了一些空闲时间来尝试并用我发现的有趣和有趣的技术构建新事物。 在这里或在GitHub上跟随我的探索之旅。

参考文献 (References)

  • Small getopts tutorial

    小getopts教程

  • How to output a multiline string in Bash

    如何在Bash中输出多行字符串

翻译自: https://www.freecodecamp.org/news/functional-and-flexible-shell-scripting-tricks-a2d693be2dd4/

shell脚本技巧

你可能感兴趣的:(字符串,编程语言,python,java,linux)