These eight recommendations come from some of the experience and lessons learned by key writers in writing shell scripts over the years. In fact began to write the time is not only these several, and later thought repeatedly, remove a few irrelevant, and finally left eight. It is no exaggeration to say that each one is carefully selected, although a few are commonplace.
1. Specify bash
The first line of the shell script, what should be after #!?
If you ask someone about this question, the answers may vary from one person to another. I've seen Www.1.qixoo.com/usr/bin/env bash,/bin/bash,/usr/bin/bash,/bin/sh, and/usr/bin/env Sh. This is the programming world "' anise ' word four ways."
In most cases, all five of these formulations are equivalent. However, people who have written the program know that "in a few cases" often hides unexpected pits.
What if the default shell of the system is not bash? For example, a Linux distribution version, the default SH is not bash.
What if the system bash is not in/usr/bin/bash?
I recommend using/usr/bin/env Bash and/bin/bash. The former adds a middle layer through env, allowing Env to search for bash in $path, which is the official endorsement of the conventional Bash location, and/usr/bin/bash is just a symbolic link to it.
2. Set-e and Set-x
OK, after some discussion, the first line is now settled. Now it's time to start writing the second line?
Wait! Before you begin to conceive and write down specific code logic, insert a line of SET-E and a line of set-x.
Set-x will output the executed content when executing each line of the shell script. It allows you to see the current execution, and the variables involved will be replaced with actual values.
SET-E will end the program in the execution of an error, just like "throw exceptions" in other languages. (accurately, not all errors will end the program, see note below)
Note: The conditions of the SET-E end program are more complex, in Man Bash, a full use of a word to describe various scenarios. Most executions exit when an error occurs, unless the shell command is in the following situation:
A non-ending part of a pipeline, such as Error | Ok
A non-ending part of a combined statement, such as OK && Error | | Other
A non-trailing part of a series of statements, such as error; Ok
In the judgment statement, including Test, if, while and so on.
These two combinations are used together and can save you a lot of time when you debug. For defensive programming reasons, it is necessary to insert them before writing the first line of specific code. Ask yourself, what is the number of times you can write a pair of code at a time? Follow the public number: programmers are free to receive video tutorials for big coffee. Most code, before committing, usually undergoes a process of repeatedly debugging changes. Rather than introducing these two configurations at the time of your own time, it's better to leave debug at the beginning. After the code can finally be submitted, it is not too late to consider whether to keep them.
3. Bring the Shellcheck
OK, now I have three lines (boilerplate) code, the specific business logic does not write a line. Is it time to start writing?
Wait! 工欲善其事, its prerequisite. This time, I'll introduce a shell scripting artifact: Shellcheck
Ashamed to say, although I wrote a few years shell script, some grammar I still can't remember clearly. This time will rely on Shellcheck guidance.
Shellcheck can also check out the common bad code for shell scripting, in addition to alerting you to grammatical problems. Originally my n advice, there are a few of these bad code, but considering that Shellcheck can fully explore these problems, so painful to remove them all out. There is no doubt that the use of Shellcheck has brought a huge leap to my shell writing skills.
The so-called "standing on the Shoulders of giants", although we recruit eggs, skills than veterans strong, but we can catch each other on the equipment Ah! Do a hands-on installation, you can get acquainted with a "teacher", why not?
By the way, Shellcheck was actually written in Haskell. Who says Haskell can only be used for faking?
4. Variable expansion
In a shell script, you can occasionally see this: Echo $xxx | Awk/sed/grep/cut .... Looks like a big picture of the situation, in fact, just want to change the value of a variable.
Why use sledgehammer to kill chickens? Bash built-in variable expansion mechanism is enough to meet your various needs! Or the old way, read the f**k manaul! Man bash then search for parameter Expansion, here's the trick you want. Key has also written a related article, hoping to help a helping hand: play the bash variable
5. Note the local
As the code writes more, you begin to refine the repetitive logic into functions. It's possible that you'll fall into a hole in bash. In bash, if the local qualifier is not added, the variables are all global by default. Variable Default global-this is similar to JS and Lua, but few bash tutorials tell you the truth from the start. In a top-level scope, it is not important whether a global variable is. But inside the function, declaring a global variable can contaminate other scopes (especially if you don't notice it at all). Therefore, it is important to remember to add the local qualifier for variables declared within a function.
6. Trap Signal
If you have written a slightly more complicated program running in the background, you should know what the POSIX standard "signal" is. If you don't know, just look at the next paragraph. Like other languages, the shell also supports processing signals. Trap Sighandler int can call the Sighandler function when the SIGINT is received. How to capture other signals and so on.
However, the main application scenario of trap is not which signal to capture. The trap command supports "capturing" many different processes--precisely, allowing the user to inject function calls into a particular process. The most common of these is the trap func exit and trap func ERR.
Trap Func exit allows you to invoke a function at the end of the script. Since the registered function can be called regardless of normal exit or abnormal exit, in the scenario where a cleanup function needs to be called, I use it to register the cleanup function instead of simply invoking the cleanup function at the end of the script.
Trap Func ERR allows a function to be called when an error is run. A common technique is to use the global variable error to store the error message and then complete the corresponding error report in the registered function based on the stored value. It is sometimes miraculous to concentrate the original fragmented error-handling logic in one place. Remember, however, that when the program exits abnormally, it calls both the function of exit registration and the function that err registers.
7. Think Twice
The above are specific recommendations, leaving two more retreats.
The suggestion was named "Think Twice". In fact, no matter what code to write, even if only a supporting script, should be think twice, avoid carelessness. No, this is more to remember when writing scripts. Many times, after all, a complex script starts with a few lines of small commands. The person who started writing this script may think it's just a one-time task. Some assumptions about external conditions are unavoidable in the code, which may be normal at the time, but as the external environment changes, these become hidden reefs. To make matters worse, almost no one will test the script. Unless you run it, you don't know if it will work.
To slow down the decay of your script code, you need to discern what is dependent and what the script will do when you write. To have the proper abstraction, write the code that can be changed, and at the same time be aware of defensive programming and give your code a moat.
8. Weaknesses
In some cases, scripting with the shell means it's hard to transplant, it's difficult to do a uniform error handling, and it's hard to process data cleanly.
Although the use of external commands can quickly and easily achieve a variety of complex functions, but as the flip side of the coin, you have to rely on grep, SED, awk and other tools to glue them together.
If you have a multi-platform-compatible requirement, be careful to avoid weird pitfalls like BSD and GNU Coreutils,bash version differences.
The lack of a well-developed data structure and consistent Api,shell scripts are not enough to handle complex logic.
Use the right tools to solve specific problems. Knowing when to use the shell and when to switch to another more generic scripting language (such as Ruby/python/perl) is the trick to writing a reliable shell script. If your task can be combined with common commands to complete, and only involves simple data, then the shell script is the right hammer. If your task contains more complex logic, and the data structure is complex, then you need to write scripts in languages such as Ruby/python.
Eight tips for writing a reliable Linux shell script