• Linux Bash Shell编程（零）：序与索引 序   本Linux Bash Shell编程教程共10节，主要为没有编程基础的运维工作者或想学习Linux Bash脚本的新手而写。教程中含有许多样例参考，全部都是可以执行的命令行或是完整...
Linux Bash Shell编程（零）：序与索引
序

本Linux Bash Shell编程教程共10节，主要为没有编程基础的运维工作者或想学习Linux Bash脚本的新手而写。教程中含有许多样例参考，全部都是可以执行的命令行或是完整经过测试的Bash脚本文件，方便大家通过样例直观学习语法。内容较为基础简单（请大佬勿喷）；但对较深入但我认为没有重要作用的内容（如函数等）没有写入，如果需要的话一段时间后可能会更新。本教程一定意义上也是笔者学习Linux Bash Shell 的笔记，希望与大家分享、共同进步，感谢大家的支持！

索引

Linux Bash Shell编程（一）：Shell概述与Hello World实现
Linux Bash Shell编程（二）：Bash基本功能（历史、补全、快捷键）
Linux Bash Shell编程（三）：重定向、多命令顺序、通配符、特殊符号
Linux Bash Shell编程（四）：变量（上） 变量分类与相关操作
Linux Bash Shell编程（五）：变量（下）变量运算、内容替换、环境变量配置文件
Linux Bash Shell编程（六）：正则表达式 基本元字符应用示例
Linux Bash Shell编程（七）：字符串截取与处理（cut、printf、awk、sed）
Linux Bash Shell编程（八）：条件判断与示例
Linux Bash Shell编程（九）：流程控制语句（上） 分支语句（if、case）
Linux Bash Shell编程（十）：流程控制语句（下） 循环语句（for while until）


展开全文
• ## Linux下BashShell编程

千次阅读 2013-02-21 23:44:59
Linux下Bash Shell编程   Bash what? 进阶的内容是什么？ Okay, I grant that this page mightrepresent a leap from the familiar to the alien without much warning. Here aresome expl
Bash Shell Programming in Linux
Linux下Bash Shell编程

Bash what?
进阶的内容是什么？
Okay, I grant that this page mightrepresent a leap from the familiar to the alien without much warning. Here aresome explananatory notes:

好吧，我承认，本页内容可能在没有给你足够警告的情况下，带领你从熟悉程度飞跃到更高阶段（难道alien是火星人？）下面有一些解释说明：

UnderLinux, there are some powerful tools that for all practical purposes areunavailable under Windows (I can imagine all the old Linux hands saying"Duh!").

在Linux中，有很多Windows中没有的强大的工具用于实用目标（可以想象所有Linux老用户喊“咄”的情景）。
·        One of these tools is something called"shell programming". This means writing code that a command shellexecutes.
·        这些工具中的一个被称为“shell编程”。就是说命令外壳执行编写的代码。
·        There is something like this underWindows, but as usual, the Windows version is a weak imitation.
·        在Windows下，有一些类似的工具，不过一般情况，Windows版本是薄弱的纺织品。
·        The most common Linux shell is named"Bash". The name comes from "Bourne Again SHell," which, inturn ... (imagine a lengthy
recursion terminating in a caveman's grunt).
·        Linux最常见的外壳程序名为“Bash”。名称来自于“Bourne
Again SHell”。这个，要反过来说..（设想一个漫长的递归终结于穴居人的咕噜）。
·
·        There are many other shells available.Unless there is a compelling reason not to, I recommend that people stick tothe Bash
shell, because this increases the chance that your scripts will beportable between machines, distributions, even operating systems.
·        也有很多其他可用的外壳程序。没有特别原因时，我建议大家专注于Bash程序，因为它能提升你的脚本在服务器、发布甚至操作系统上的移植机会。

·        I'll be showing some very basic examplesof Bash shell programming on this page, and I want to say at the outset thatshell
programming is an art, not a science. That means there is always someother way to do the same thing.
·        我会在本页展示一些非常基础的Bash shell编程例子，并且我起初想说的是，Shell编程是一门艺术，而不是技术。也就是说，总有很多其他方式实现相同的目的。
·
·        Because shell programming is an art,please don't write to say, "Wow, that was a really inefficient way to dosuch-and-such."
Please do write (message page) to report actual errors.
·        由于shell编程是一门艺术，请不要写信说“哦，Shell在做这样或那样的事情时真的很没效率”。请写（信息页）报告实际的错误。
·
·        如果本页的信息看起来太简单，太初级的话，可以从中选择更高级的资源。

Introduction
简介
·        Early computers had a teletype machinewith a keyboard for I/O. Later, glass terminals became the norm, but thebehavior
was much the same — a keyboard, a screen, a text display. A programwas responsible for mediating the transaction between the operator and themachine, and as the years passed this program (the command interpreter orshell) became more sophisticated.
·        早期计算机有一个打字机，使用键盘进行I/O。后来，纯平显示终端普及，但是行为却非常相似—一个键盘，一个显示器，一个文本显示器。程序衔接操作人和机器之间的事务，并且经历多年之后，程序（命令解析或者shell）也变得越来越复杂。
·        At this stage the command shell has becomerather too sophisticated, typically having a dozen ways to do any particularthing.
In this page I will try to limit myself to describing a handful ofuseful operations, based not on listing everything that can be done, but onsolving specific problems. There are some at the bottom of this page for thosewanting more depth.
·        现阶段，命令行变得太复杂，尤其有很多方式特定的事情。在本页，我会在不列举所有的操作但是能解决问题的基础上，尝试限制自己去描述一些有用的操作。有些更有深度的信息在本页的底部。
·
Preliminaries
写在正文之前
·        There are two primary ways to use theshell: interactively and by writing shell scripts.
·        使用shell有两种主要方式：交互式和编写shell脚本的方式。
o   In theinteractive mode, the usertypes a single command (or a short string of commands) and the result isprinted out.
o   在交互模式中，用户输入单个命令（或者短的命令字符串），然后结果被输出。
o   Inshell scripting, the user typesanything from a few lines to an entire program into a text editor, then executesthe
resulting text file as a shell script.
o   使用shell脚本时，用户输入几行代码或者整个程序到编辑器中，然后以shell脚本方式运行。
o   It is often the case that an interactivesession becomes a shell scripting session, once things get too complicated forsimple
interactive line entries, or because a specific sequence of commandsappears to be generally useful and worth preserving.
o   交互模式的会话常常逐步变成了shell脚本的会话，一旦需求在单一交互式入口变的复杂，或者由于代码的特定顺序变得有用，并且需要被保障时。
·        In a modern Linux environment the user canhave more than one shell open at a time, either by moving between a sequence
ofindependent "virtual terminals" in a text-only environment, or byopening any number of shell windows in the X Windows environment.
·        现在，在Linux环境下，用户可以同时打开多个shell，要么在多个独立文本环境的虚拟终端间切换位置，要么在多窗口环境中打开多个shell窗口。
·
·        The advantage of having more than oneshell available is that one shell can be used for testing one command at atime, while
another might provide a text editor for assembling single commandsinto a shell program.
·        同时可以有多个有效shell脚本的优点是，可以在一个文本编辑器编写代码到程序的同时，另一个窗口用于命令测试。

·        I don't want to get toodistribution-specific, but if you are not hosting X Windows and want more thanone simultaneous shell
session, with many current distributions you can switchbetween "virtual terminals" by pressing Ctrl+Alt+F(n), n typicallybetween 1 and 6.
·        我不想搞特殊分配，但如果你没有使用多窗口模式并且想同时操作多个shell会话，在很多现在的版本中，可以使用Ctrl+Alt+F（n）在多个虚拟终端间切换，n通常在1到6。
·
·        In an environment that supports X Windows,simply open any desired number of command shell windows and move between them.
·        在支持多窗口模式的环境，直接打开多个shell命令窗口，并且可以在窗口间切换。

Simple Stuff
简单例子
·        First, a convention. I'll list things foryou to type in this format:
·        首先，按照惯例，我会按照下面格式列出你需要输入的内容：

$date  I will list the computer's reply like this: 我会按下面格式列出计算机的响应： Tue Dec 23 10:52:51 PST 2003 Notice the "$" symbol in the user entry above. This is a genericshell prompt, and yours will almost certainly look different (but it willinclude a similar symbol).
I'll be using one of two prompts (this is a commonconvention, worth remembering): I'll use "$" to refer to a normaluser session, and "#" to refer to a root session. 注意上面的“$”符号是用户输入。这是个常规的shell符号，当然肯定也可以看到其他不同的符号（不过会包含类似的符号）。我会用一到两种符号（这是个常见的习惯，值得记住）：我会用“$”提交到用户会话，用“#”提交root会话。 · NOTE:Avoid using root sessions and permissions unless it is required.Misused root authority can cause very serious harm to your system. Since thisis a tutorial in which you will want to experiment with different commands,limit the chance for harm by doing so as an ordinary user. · 注意：避免使用root会话和权限，除非需要这些权限。误用root认证会导致对系统非常严重的破坏。因为这是你以后使用不同命令的经验，使用普通用户权限可以减少系统被破坏的机会。 · · To put this another way, enter thisexample: · 使用另一种方式确定，输入下面例子： # whoami root If your session produced the result shown above, please — log out andbecome an ordinary user. 如果你的会话生成上面显示的结果，请—注销后以普通用户登录。 · In shell programming,spaces matter. If you see spaces between words andcharacters in these examples, be sure to include the spaces. · 在shell编程中，空格问题。如果你在例子的字和字符间看到空格，请确信包含这些空格。 · In shell programming,case matters also. If you don't get the results shown onthis page, look at the case of your entries. · 在shell编程中，也有大小写问题。如果没有获取到结果，查看输入的大小写。 Where are you? 你在哪儿？ · As you may be aware, a Linux filesystem isin the form of a large tree with many branches called"subdirectories". When you issue a shell command, it is oftennecessary to know where you are in the "tree". Type this example: · 你可能意识到了，Linux的文件系统是一个巨大的树形结构，包含了很多称为“子目录的”分支。当你使用shell命令时，通常需要知道你在这个“树”中的位置。输入下面的例子： $ pwd

/path/path/path
When you try this example ("pwd" means "print workingdirectory"), your current working directory will be printed.
当你尝试这个例子（“pwd”表示“打印工作目录”），你当前的工作路径会被打印出来。
·        You can decide where you are in the tree.Type this example:
·        可以决定在树形路径的位置，输入以下例子：

$cd ~$ pwd

The symbol "~" is a special shortcut character that can be usedto refer to your home directory. You could have typed this —
符号“~”是特定的可以用于应用到用户的home路径的快捷方式。可以输入：
$cd /home/username — and accomplished the same result, but if you think about it, the"~" character is more portable. Later, when you are writing shellscripts, you might want a command that moves to any user's home directory. —会达到相同的效果，但如果考虑以下的话，“~”字符更方便。以后，当你编写shell脚本时，你可能希望有个命令可以移动到任何用户的home路径。 Listing Files 文件列表 · Directories contain files, and you canlist them in a simple, compact format: · 目录包含文件，可以以简单，简洁的格式列出文件： $ ls

filename filename filename ...
Or you can list them in more detail:
或者，列出更详细的信息：

$ls -la (detailed list, one file per line) And, very important, to find out what a command's options are, use the"man" (manual) command: 还有，非常重要的是，使用“man”命令查看命令的选项： $ man ls

(manual page for "ls")
NOTE:The "man" command allows youto learn a command's options. You still have to remember the command's name.
注意：“man“命令让你学习命令的选项。你依然需要记住命令的名称。
To find files by name:
根据名称查找文件:

$find . -name '*.jpg' (list of files with .jpg suffix in currentand all child directories) （列出在当前目录和所有子目录中的.jpg后缀的文件。） To create a text diagram of the directory tree: 创建目录树的文本图表： $ tree -d .

(diagram of the directory tree from thecurrent directory)
（从当前路径得到的路径图表）
The "tree" command is less useful now that directory trees havebecome so complicated, and now that most distributions support X Windows andsophisticated filesystem
browsers.
“tree“，命令没那么有用了，现在的目录树已经变得很复杂并且现在多数发布版本都支持多窗口和复杂的文件系统浏览器。
Examining Files
检查文件
·        There are a number of things you can do tofind out more about the files in the list. Here are just a few:
·        要找出文件列表中更多的信息，有很多事情要做。下面是少部分：
The "file" command tries to identify files by examining theircontents:
“file“命令通过检查文件内容标志文件。

$file tux_small.png tux_small.png: PNG image data, 128 x 151,8-bit/color RGB, non-interlaced The next example uses the obscurely named "cat" command. Itprints the contents of a file. Unfortunately if the file's contents are notreadable, they get printed anyway. 下一个例子隐式使用名为“cat”的命令。它打印文件内容。很不幸运，如果文件内容不可读，它也会打印出来（乱码）。 $ cat zipcodes.txt

(prints the entire contents of a filenamed "zipcodes.txt")
If a file is too long to be viewed on one page, you can say:
如果文件太长而不能在一页内查看，可以输入：

$more zipcodes.txt (prints file one screenful at a time) You can also use "grep" to print only those parts of a file youare interested in: 也可以使用“grep”只打印那些你感兴趣的部分： $ grep 10001 zipcodes.txt

(prints only those lines that have thecharacter string "10001" in them)
The "grep" command is very useful, unfortunately it has adifficult-to-remember name. Be sure to:
“grep”命令非常有用，不巧的是它有个很难记住的名字一定要:
$man grep There are many, many more shell commands tolearn and to use. You may want to browse the list of for more detail. 有很多shell命令需要学习和使用。你可能需要浏览更加详细的列表。 Pipelines andRedirection · You can use apipeline (symbolized by "|") to make the output of one command serveas the input to another command. This idea can beused to create a combination of commands to accomplish something no singlecommand can do. · 可以使用管道（使用“|”符号标识）将一个命令的输出作为另一个命令的输入。这个方法用于创建合并的命令集以完成一些单个命令无法完成的事情。 · Enter this command: 输入命令： $ echo "cherry apple peach"

cherry apple peach
Okay, let's say we want to sort these words alphabetically. There is acommand "sort", but it sorts entire lines, not words, so we need tobreak this single line into
individual lines, one line per word.
好的，比方说我们想要按字母顺序排列这些单词。有一个”sort”命令，但是会排序整行数据，而不是按单词排序，所以我们需要将这行内容分成独立的行，每行一个单词。
Step one: pipe the output of "echo" into a translation (tr)command that will replace spaces with linefeeds (represented by"\n"):
第一步：导入“echo”命令的输出信息到“tr”命令，“tr”会使用换行（用“\n”表示）替换空格：

$echo "cherry apple peach" |tr " " "\n" cherry apple peach Success: each word appears on a separate line. Now we are ready to sort. 成功：每个单词输出一行。现在我们可以排序了。 Step two: add the sort command: 第二步：添加排序命令： $ echo "cherry apple peach" |tr " " "\n" | sort

apple
cherry
peach
Let's try reversing the order of the sort:
我们尝试翻转排序顺序：

$echo "cherry apple peach" |tr " " "\n" | sort -r peach cherry apple · Remember:A pipeline ("|") takes the output of one command and makesit the input to another command. · 请记住：管道（“|”）获得一个命令的输出并且将输出作为另一个命令的输入。 · Normally the output from commands isprinted on the screen. But using the symbol ">", you can redirectthe output to a file: · 一般情况，命令的输出会被打印到屏幕。但是使用“>”，可以将输入导出到文件。 $ date > RightNow.txt
$cat RightNow.txt Tue Dec 23 14:43:33 PST 2003 The above example used ">" to replace the content of anyexisting file having the name "RightNow.txt". To append new data toan existing file, use ">>" instead: 上面的例子使用“>”替换名为“RightNow.txt”的文件内容。要增加新的信息到文件中，使用“>>”替代： $ date >> RightNow.txt
$cat RightNow.txt Tue Dec 23 14:43:33 PST 2003 Tue Dec 23 14:46:10 PST 2003 · Remember:Use ">" to overwrite any existing file, use">>" to append to any existing file. In both cases, if nofile exists, one is created. · 请记住:使用“>”覆盖任何已存在文件内容，使用“>>”增加内容到已存在文件。相同的是，如果文件不存在，会创建文件。 · Many commands have inputs as well asoutputs. The input defaults to the keyboard, the output defaults to the screen. · 很多命令有输入也有输出。输入默认通过键盘，输出默认到屏幕。 · To redirect the output to a file, use">" or ">>" as shown above. · 要转存输出到文件中，使用如上所示的“>”或“>>”。 · To make the output of acommandserve as the input of another command, use "|". · 要使一个命令的输出作为另一个命令的输入，使用“|”。 · To make the contents of afileserve as the input to a command, use "<": · 要使一个文件的内容作为命令的输入，使用“<”: $ wc < RightNow.txt

2 12 58

As is so often the case in shell programming, there is at least one otherway to produce the above result:
Shell编程中常常有这种情况，至少有另一种方法达到上边的结果:

$cat RightNow.txt | wc 2 12 58 Shell Script Basics Shell脚本基础 · A shell script is a plain-text file thatcontains shell commands. It can be executed by typing its name into a shell, orby placing its name in another shell script. · Shell脚本时包含shell命令的文本文件。可以在通过输入文件名到shell执行，或者在另外一个shell脚本中使用它的名称。 · To be executable, a shell script file mustmeet some conditions: · 要作为可执行文件，shell脚本文件必须满足一些条件： o The file must have a special first linethat names an appropriate command processor. For this tutorial, the followingwill work in most cases: o 文件必须有特定的首行，确定一个合适的命令处理器。本片指导中，大多数情况使用下面的内容： #!/bin/bash If this example doesn't work, you will need to find out where your Bashshell executable is located and substitute that location in the above example.Here is one way to find out: 如果这个例子不能运行，你需要找出Bash shell可执行文件加载的路径并替换上面例子的路径。下面是一种确定方法： o The file must be made executable bychanging its permission bits. An example: o Bash shell文件必须通过改变权限位的方式使它成为看执行文件。例如： $ chmod +x (shell script filename)

·        A shell script file may optionally have anidentifying suffix, like ".sh". This only helps the user rememberwhich files
are which. The command processor responsible for executing the fileuses the executable bit, plus the file's first line, to decide how to handle ashell script file.
·        Shell脚本文件可以使用标志性的扩展名，如：“.sh”。这个仅能帮助用户记忆文件类型。命令响应处理器使用文件的可执行控制位，添加在文件的第一行，以决定shell文件的处理方式。
·        One normally executes a shell script thisway:
·        一般使用下面方式运行shell脚本：
$./scriptname.sh This special entry is a way to tell the command processor that the desiredscript is located in the current directory. Always remember: if you cannot getyour shell script to run, remember this trick to provide its location as wellas its name. 这种方式是告知命令处理器，它要处理的脚本位于当前路径。一定要记住：如果shell脚本不能运行，记得这招：提供文件名称时，也提供它的路径。 First Shell Script 第一个Shell脚本 · This will get you past the details ofwriting and launching a simple script. · 下面让你通过编写和调用简单shell脚本的细节。 1. Choose a text editor you want to use. Itcan be a command-line editor like emacs, pico or vi, or an X Windows editor ifyou have this option. 2. Run your choice of editor and type thefollowing lines: 3. 4. #!/bin/bash 5. echo "Hello, world."  6. 1.选项你想用的文本编辑器。可以是emacs、pico、vi这样的命令行编辑器，或者是多窗口的编辑器（如果你有的话）。 2. 运行编辑器，并输入下面内容： 3. NOTE:Be sure to place a linefeed at the endof your script. 注意：请确定在你脚本的结尾添加换行符。 Forgetting a terminating linefeedis a common beginner's error. 忘记结束的换行符是新手常见的错误。 6. Save the file in the current workingdirectory as "myscript.sh". 7. Move from the text editor to a commandshell. 8. From the command shell, type this:$ chmod +x myscript.sh
9.   To execute the script, type this:
$./myscript.shHello, world. · These steps will become second nature soonenough. Tests and Branching · Bash shell scripts can perform, and act on,various kinds of tests. This will be just the most basic introduction — see thereference material at for more on this rather baroque topic. · To follow these andother examples that involve multiline shell scripts, please set up to edit andrun a test script file (let's call it "myscript.sh") that you can useto enter and test various options. And remember that the examples won't includethe all-important first line of the script (see script examples above) — itwill be assumed to exist in each case. Also, to save time, you may want to copy some of the shell code examplesfrom this page directly into your editor. · Here is an example of a test and branch: · · if [-e . ] · then · echo "Yes." · else · echo "No." · fi · Run the test script:$ ./myscript.shYes.
We created a test (the part of the script between "[" and"]") which tested whether a particular element existed("-e"). Because the symbol "." in this context means
thecurrent directory, the test succeeded. Try replacing the "." withsomething that is not present in the current directory, example"xyz". See how the outcome changes.
It is important to realize that "[" is an alias for the command"test". The script could have been written as:

if test -e .
then
echo "Yes."
else
echo "No."
fi

NOTE: Be sure to read the "test" manpage to find out all the different tests that are available:
$man test Before we move on, there is a perversity about tests in Bash shells that Iwant to discuss. It turns out, because of a historical accident that now mightas well be cast in concrete, when a test is conducted or a command returns aresult value, the numerical value for "true" is 0, and"false" is 1. Those of you who have some programming experience willlikely find this reversal of intuition as annoying as I do. Here is a way to get the result of the most recent logical test (and toshow the weird reversal described above):$ test -e .$echo$?0
$test -e xyz$ echo $?1 Please remember this reversal, because it confounds the process ofthinking through, and constructing, logical tests. For example, you may want towrite a shortcut form for a test that only acts on one kind of result:$ test -e . && echo"Yes."Yes.
This sort of shorthand relies on some knowledge of logical processing — ifthe left-hand part of an AND test yields "true", then the right-handpart must also be evaluated,
and so it is. But the numerical "true"value for the left-hand test is 0, which would argue for the opposite logic.
Just to show how perverse this all is, here is an example of Bash logicaltesting that comes out the opposite way:
$echo$(( 0 && 0 ))0
$echo$(( 1 && 0 ))0
$echo$(( 0 && 1 ))0
$echo$(( 1 && 1 ))1
Yes, just as you would expect. So do be on guard against this shell"gotcha", which only affects the outcome of tests and command resultvalues. It probably will not
surprise you to learn that no one mentions thisstrange anomaly in the official Bash documentation.
A couple of rules about logical operators used as branches:
o   If you write "test &&command", the command will only be executed if the testsucceeds.
o   If you write "test || command",the command will only be executed if the testfails.
Run these tests:
$true && echo "Yes."Yes.$ false || echo "Yes."Yes.
Notice that the outcomes are entirely in keeping with one's intuitionabout such logical comparisons, and all is well as long as you don't thinkabout the fact that
true equals 0. :)
Here's another scheme commonly seen in shell script programming andinteractive sessions:
$command1 && command2 &&command3 && command4 This line of code will not run the next command in the sequence unless theprior command has returned "true", meaning no errors. It is a way toavoid running a command if a required prior outcome is not present. Loops andRepetition · Here are some examples of loop operators: · · for fnin *; do · echo "$fn"
·        done
·

In this example, the "*" is expanded by the shell to a list ofall the files in the current directory, then each filename is applied to theloop control area. In such
a construct, any whitespace-delimited list will do:

for fn in tom dickharry; do
echo "$fn" done$ ./myscript.shtomdickharry
This method will work for any list that uses spaces as delimiters. Butwhat happens if you must parse a list that must be delimited by linefeedsinstead of spaces,
such as the case of a list of filenames or paths thatcontain spaces as part of their names?
You can solve such a problem this way (there are other solutions):

ls -1 | while readfn; do
echo "$fn" done This example uses an option to "ls" (note: the option is"-" followed by the numerical digit "1",not alowercase "L") that formats file listings with one name per line,then this list is pipelined to a routine that reads lines until there are nomore to read. This meets the requirement that linefeeds become the delimitersbetween list elements, not spaces. There is plenty more to this topic. Please refer to the list of for more. Using Numbers inScripts · Contrary to a sometimes-expressed view,numbers can easily be accommodated in scripts. Example: · · n=1 · while[$n -le 6 ]; do
·            echo $n · let n++ · done ·$ ./myscript.sh123456
Notice the "let" command, which treats its argument in a waymeant to accommodate numbers.
Here is a somewhat more complex example:

y=1
while [ $y -le 12 ];do x=1 while [$x -le 12 ]; do

printf "% 4d" $(($x * $y)) let x++ done echo "" let y++ done$ ./myscript.sh

1  2   3   4  5   6   7  8   9  10 11  12
2  4   6   8 10  12  14 16  18  20 22  24
3  6   9  12 15  18  21 24  27  30 33  36
4  8  12  16 20  24  28 32  36  40  44  48
5 10  15  20 25  30  35 40  45  50 55  60
6 12  18  24 30  36  42 48  54  60 66  72
7 14  21  28 35  42  49 56  63  70 77  84
8 16  24  32 40  48  56 64  72  80 88  96
9 18  27  36 45  54  63 72  81  90  99108
10  20  30 40  50  60 70  80  90 100 110 120
11 22  33  44 55  66  77 88  99 110 121 132
12 24  36  48 60  72  84  96108 120 132 144

Coping with userinput
·        Here is an example that relies on userinput to decide what to do. It exploits a shell feature as an easy way tocreate a
·
·        PS3="Choose(1-5):"
·        echo"Choose from the list below."
·        selectname in red green blue yellow magenta
·        do
·            break
·        done
·        echo"You chose $name." · When run, it looks like this:$ ./myscript.sh

Choose from the listbelow.
1) red
2) green
3) blue
4) yellow
5) magenta
Choose (1-5):4
You chose yellow.

As written, this menu code won't catch some kinds of errors (like a numberthat is out of range). In any application where the user choice must fall intodefined bounds,
be sure to perform a test on the result before using it.Example:

if ["$name" = "" ]; then echo "Error in entry." exit 1 fi An advanced example with numbers and user input · Here is an example guessing game that tiestogether some of the elements we've covered so far: · · secretNumber=$((((date +%N / 1000) % 100) +1 ))
·        guess=-1
·        while[ "$guess" != "$secretNumber" ]; do
·            echo -n "I am thinking of a numberbetween 1 and 100. Enter your guess:"
·            if [ "$guess" = "" ];then · echo "Please enter anumber." · elif [ "$guess" ="$secretNumber" ]; then · echo -e "\aYes!$guess is thecorrect answer!"
·            elif [ "$secretNumber" -gt"$guess" ]; then
·                    echo "The secret number islarger than your guess. Try again."
·            else
·                    echo "The secret number issmaller than your guess. Try again."
·            fi
·        done
·

Please study this example carefully, and refer to the reference materialsin to understand some of the methods.
Creating and usingarrays
·        Shell arrays are relatively easy toconstruct. Example:
·
·        array=(redgreen blue yellow magenta)
·        len=${#array[*]} · echo"The array has$len members. They are:"
·        i=0
·        while[ $i -lt$len ]; do
·            echo "$i:${array[$i]}" · let i++ · done · Run this example:$ ./myscript.sh

The array has 5members. They are:
0: red
1: green
2: blue
3: yellow
4: magenta

Now, before you decide this is a silly, rather useless example, replaceone line of the script and run it again:

array=(ls)

See what difference this makes (and think of all the kinds of lists youmight create for this line).
Strings andsubstrings
·        It's useful to be able to take stringsapart and put them together in different ways. Here is how to select asubstring from
a string:
·
·        string="thisis a substring test"
·        substring=${string:10:9} · In this example, thevariable "substring" contains the word"substring". Remember this rule: substring=${string_variable_name:starting_position:length}

The string starting position is zero-based.
Searching and Replacing Substrings within Strings
·        In this method you can replace one or moreinstances of a string with another string. Here is the basic syntax:
·
·        alpha="Thisis a test string in which the word \"test\" is replaced."
·        beta="${alpha/test/replace}" · The string "beta" now contains an edited version of the originalstring in which thefirst case of the word "test" has beenreplaced by "replace". To replace all cases, not just thefirst, use this syntax: beta="${alpha//test/replace}"

Note the double "//" symbol.
Here is an example in which we replace one string with another in amulti-line block of text:

list="cricketfrog cat dog"
poem="I wanna bea x\n\
A x is what I'd loveto be\n\
If I became a x\n\
How happy I wouldbe.\n"
for critter in $list;do echo -e${poem//x/$critter} done Run this example:$ ./myscript.sh

I wanna be a cricket
A cricket is what I'dlove to be
If I became a cricket
How happy I would be.
I wanna be a frog
A frog is what I'dlove to be
If I became a frog
How happy I would be.
I wanna be a cat
A cat is what I'dlove to be
If I became a cat
How happy I would be.
I wanna be a dog
A dog is what I'dlove to be
If I became a dog
How happy I would be.

Silly example, huh? It should be obvious that this search & replacecapability could have many more useful purposes.
More obscure but useful string operations
·        Here is a way to isolate something usefulfrom a large, even multi-line, string. As above, this method relies onenclosing
a variable name in curly braces, then aplying a special operator toachieve a particular result.
Here is a list of four such operators:
o   Operator "#" means "deletefrom the left, to the first case of what follows."
o
o  $x="This is my test string." o$ echo ${x#* } o o is my test string. o o o Operator "##" means "deletefrom the left, to the last case of what follows." o o$ x="This is my test string."
o  $echo${x##* }
o
o  string.
o
o

o   Operator "%" means "deletefrom the right, to the first case of what follows."
o
o  $x="This is my test string." o$ echo ${x% *} o o This is my test o o o Operator "%%" means "deletefrom the right, to the last case of what follows." o o$ x="This is my test string."
o  $echo${x%% *}
o
o  This
o
o

I find these operators particularly useful in parsing multi-line strings.Let's say I want to isolate a particular IP address from the output of the"ifconfig" command.
Here's how I would proceed:

$x=/sbin/ifconfig$ echo $x eth0 Link encap:Ethernet HWaddr 00:0D:56:0C:8D:10 inet addr:192.168.0.1 Bcast:192.168.0.255 Mask:255.255.255.0 inet6 addr:fe80::20d:56ff:fe0c:8d10/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:253339 errors:0 dropped:0overruns:0 frame:0 TX packets:423729 errors:0 dropped:0overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:36150085 (34.4 MiB) TX bytes:496768499 (473.7 MiB) Base address:0xecc0Memory:fe4e0000-fe500000 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:109394 errors:0 dropped:0overruns:0 frame:0 TX packets:109394 errors:0 dropped:0overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:12372380 (11.7 MiB) TX bytes:12372380 (11.7 MiB) There's lots of information, more than we need. Let's say for the sake ofargument that I want the IP of "lo", the loopback interface. I couldspecify this:$ y=${x#*inet addr:} But, while gobbling text from the left, this search would stop at the IPaddress of eth0, not the desired interface. So I can specify it this way:$ y=${x#*lo *inetaddr:} As a last step I'll trim off all remaining text to the right:$ y=${y%% *} Leaving only the desired address. It seems the "#" and "%" operators, and theirvariants, are able to accept a rather complex argument and sort through thecontent of large strings, including strings with line breaks. This means I canuse the shell to directly filter content in some simple cases where I mighthave considered using sed or Perl. Bash Version 3 I have always thought the inability to test for the presence of a stringor pattern (without using grep, sed or something similar) was a conspicuousweakness in shell programming. Bash version 3, present on must current Linuxdistributions, addresses this lack by allowing regular expression matching. Let's say we need to establish whether variable$x appears to be a socialsecurity number:

if [[ $x =~[0-9]{3}-[0-9]{2}-[0-9]{4} ]] then # process SSN else # print error message fi Notice the Perlish "=~" syntax and that the regular expressionappears withindouble brackets. A substantial number of regularexpression metacharacters are supported, but not some of the Perl-specificextensions like \w, \d and \s. Another Bash 3 feature is an improved brace expansion operator:$ echo {a..z}

a b c d e f g h i j kl m n o p q r s t u v w x y z

for n in {0..5}
do

echo $n done 0 1 2 3 4 5 Useful Links Well, as long-winded as it turned out tobe, this page is supposed to be an introduction to shell programming, one thatjust touches the highlights. The linked references below will provide a deeper understandingof the covered topics. · A quick guide to writingscripts using the bash shell (Rutgers) · Advanced Bash Scripting Guide (Linux DocumentationProject) · Bash Reference Manual (GNUProject, downloadable versions) Home | Linux | * Linux Base Adventures in Ray Tracing Bash Script Beautifier Bash Shell Programming in Linux Consistent Network Device NamingDictionary access under Linux Dictionary front end using PHP Installing Linux on a Dell XPS Laptop Mobile Internet Access Using Linux ModelinesNetworkManager NokiaNotes and Fixes for Fedora 17 Running Fedora Linux on Dell Laptops Secure Shell Fun and Games Share This Page  展开全文 • 我一直觉得写好Bash ...在这篇文章，我把自己认为一些比较好的Bash shell编程资料分享出来，希望可以给大家一点帮助。 我个人看过的最好的Bash shell编程入门资料是《Linux程序设计》的第二章：shell程序设计，看  我一直觉得写好Bash shell脚本是一件很cool的事，短短几行代码，就能完成其它编程语言几十行甚至上百行代码才能完成的功能，可惜我自己写Bash shell脚本能力实在不敢恭维。在这篇文章，我把自己认为一些比较好的Bash shell编程资料分享出来，希望可以给大家一点帮助。 我个人看过的最好的Bash shell编程入门资料是《Linux程序设计》的第二章：shell程序设计，看这一章的同时自己动手实践，我觉得入门基本没问题了。 入门之后，我建议大家一定要看CU论坛上shell大牛网中人经典的《shell十三问》系列文章，这些文章把很多shell编程tricky的东西讲的很细，很明白。我每次读都有新的收获。 关于如何调试shell程序，推荐coolshell上的文章：如何调试bash脚本，在我这篇文章结尾提到的bashdb调试器，我这几天还用了一下。虽然比起gdb还差了很远（比如没有命令自动补全功能，等等），但总体感觉还可以，可以提高调试效率。 最后推荐两个网站： http://www.shellcheck.net/：用来检测shell脚本，帮你发现问题。 http://explainshell.com/：用来帮你理解shell脚本。 好了，动手实践吧。Happy bashing! Happy hacking!  展开全文 • Linux Bash Shell编程（八）：条件判断语句与示例 上一节中，我们了解了字符串截取和处理的相关命令，可以对命令的输出数据流进行筛选截取。本节开始，就到了Bash Shell编程最关键的部分：条件判断和流程控制... Linux Bash Shell编程（八）：条件判断语句与示例 上一节中，我们了解了字符串截取和处理的相关命令，可以对命令的输出数据流进行筛选截取。本节开始，就到了Bash Shell编程最关键的部分：条件判断和流程控制语句。本节中，我们先熟悉条件判断的各种类型、形式。 条件判断的基本语法 条件判断的基本语法主要有两种：基于命令行的test命令和更适合于嵌入流程控制语句的条件样式。 test 命令 test命令以命令行的形式运行条件判断语句，不会有任何标准输出，该语句的执行结果被保存在预定义变量$?中（注意，$?值类似于程序返回值，而不是布尔型数据，$? 0为真，1为假），可以直接用echo命令查看，也可被多命令逻辑关系符调用，更符合使用者的习惯，但在Shell脚本中使用不便，一般不建议在Shell中使用

test 条件判断语句
#为了观察实际效果，一般使用echo命令查看$?预定义变量 echo$?
#0为真，1为假

#例如：(判断语句的具体分类在下面讲到)
test -e Hello_World.sh
echo $?  用[]包含的条件样式 用[]包含的条件判断表达式功能与test命令相同，不采用命令式结构，可以方便地嵌入流程控制语句中作为条件，返回值同样在预定义变量$?中，除了形式不同，其余与test命令完全相同
注意：[ ]内侧两边必须有空格，否则命令执行报错

[ 条件判断语句 ]
#同样使用echo命令查看条件判断语句结果
echo $? #例如：(判断语句的具体分类在下面讲到) [ -e Hello_World.sh ] echo$?

条件判断语句类型
按照文件类型判断
在选项后加文件名，可以判断文件（若存在）类型是否符合条件，若文件不存在直接返回假，符合条件返回真，具体文件类型判断符与ls命令结果中文件属性第一位相似
[选项 文件名]
#echo #?


选项
作用

-b
判断文件（若存在 （下同））是否为块设备文件（是为真  （下同））

-c
判断文件是否为字符设备文件

-d
判断文件是否为目录文件

-e
exist  仅判断文件是否存在

-f
file  判断文件是否为普通文件

-L
判断文件是否为符号链接文件

-p
判断文件是否为管道文件

-s
判断文件是否非空（非空为真）

-S
判断文件是否为套接字文件

按照文件权限判断
同样要在选项后加文件名，有权限为真，无权限或文件不存在为假。（判断的是当前用户对这个文件的权限）

选项
作用

-r
判断对该文件是否有读权限

-w
判断对该文件是否有写权限

-x
判断对该文件是否有执行权限

-u
判断对该文件是否有SUID权限

-g
判断对该文件/目录是否有SGID权限

-k
判断对该目录是否有SBIT权限

比较两个文件的信息
格式：文件1 [选项] 文件2

选项
作用

-nt

-ot
older than 判断文件1的最后修改时间是否比文件2早，早为真（0）

-ef
判断两个文件的Inode号是否一致，近似为两个文件是否相同

其中，Inode号是标识文件的序号，两个不同的文件可以名称相同，但Inode号不能相同，若两个文件为硬链接（保存为副本、同步更新）关系，则两文件的Inode号才会相同，其余不同
两个硬链接的文件，除了Inode号相同外没有任何标志，可以使用这个判断方式判断硬链接

比较两个整数
若为两个变量，不需要声明为整型格式，语法：整数1 [选项] 整数2

选项
作用

-eq
equal  判断两个整数是否相等

-ne
not  equal 判断两个整数是否不等

-gt
greater  than判断整数1是否大于整数2

-lt
less  than 判断整数1是否小于整数2

-ge
greater/equal  判断整数1是否大于等于整数2

-le
less/equal  判断整数1是否小于等于整数2

判断字符串相关
语法包含在选项中，注意：两个字符串比较相关的判断符两边都要加空格，否则无论如何，返回值均为真

选项
作用

-z 字符串
判断字符串是否为空

-n 字符串
判断字符串是否非空

字符串1 == 字符串2
判断两个字符串是否相等

字符串1 != 字符串2
判断两个字符串是否不等

当字符串是变量时，如果变量没有定义，则同样视作空字符串

两个判断条件的逻辑关系
同时使用两个判断条件时，要注意它们之间的逻辑关系，两个判断条件的格式：条件1 [选项] 条件2

选项
作用

-a
逻辑与，两个条件都成立才成立

-o
逻辑或，两个条件有一个成立就成立

!  [条件]
逻辑非，使判断结果取反（注意，!与条件之间有空格）

条件判断语句与多命令逻辑符连用
关于多命令顺序与逻辑符，请参阅Linux Bash Shell编程（三）：重定向、多命令顺序、通配符、特殊符号
实际上，多命令顺序与逻辑符判断前一个命令是否执行的方式就是判断预定义变量$?的值是否为0，所以可以直接将条件判断语句看作一个命令加入多命令顺序语句中，条件判断为真相当于正确执行了上一个语句。 示例 示例1，判断文件是否存在： [ -e ./test.sh ] && echo "File exists" || echo "File not found" #条件判断语句方括号内侧必须有空格 #该命令执行，若文件存在，显示"File exists"；否则显示"File not found"  示例2，用多命令逻辑符构建单行比大小程序： #以下为test5.sh中的内容 #!/bin/bash #Author：Zheng read -p "a= " a read -p "b= " b #通过键盘读入a，b数据，请参阅（四） [$a -lt $b ] && echo "a<b" || echo "a>=b"  示例3，多条件判断语句：判断输入变量是否为空并且是否值小于10 #以下为test6.sh中内容 #!/bin/bash #Author: Zheng read -p "Input a: " a #若a非空且小于10，则输出Yes [ -n$a -a \$a -lt 10 ] && echo "Yes" || echo "No"
#此脚本中未加入判断a是否为整数的条件，留待改进


索引
下一节，Linux Bash Shell编程（九）：流程控制语句（上） 分支语句（if、case），我们将学习Bash流程控制语句
上一节，Linux Bash Shell编程（七）：字符串截取与处理（cut、printf、awk、sed）


展开全文
• 一张图带你掌握bash shell编程。PDF版本下载请在公众号后台回复：【Shell】即可。推荐阅读推荐一款在线 Nginx 配置生成器推荐十款Linux网络监视工具W...
• Linux Bash Shell编程（一）：Shell概述与Hello World实现 Shell 概述   Shell是一个命令行解释器，它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序，用户可以用Shell来启动、挂起、停止并...
• Linux Bash Shell编程（二）：Bash基本功能（历史、补全、别名、快捷键）   上一节简单介绍了Linux Shell并用echo命令编写了第一个Bash脚本Hello World。本节我们来认识一下熟悉的Bash命令解释器的基本功能：命令...
• Linux Bash Shell编程（四）：变量（上） 变量分类与相关操作 上一节,我们了解了Bash中的重定向以及特殊符号，从本节开始我们来一起探索Bash中变量的奥秘。本节我们先来了解下Bash中变量的基本知识以及对变量处理的...
• ## BashShell编程基础

千次阅读 2018-03-18 17:42:37
转载请注明出处：...2）在Unix历史中，Shell作为系统的命令行调用接口，以独立的程序实现。3）早期的Shell提供了一些基本特性，供用户使用。功能逐渐完善，发展...
• Bash SHELL 中文文档,最权威的中文文档，这个文档是pdf的,做的很精致, 是官方bash指南的中文版,非扫描版. 使用及其方便,是学习linux bash的必备工具书。
• Linux Bash Shell编程（三）：重定向、多命令顺序、通配符、特殊符号   上一节我们学习了Bash中的基本功能，相信经过前两节的学习，大家平时使用Bash的效率得到了一点提高。本节，我们将继续探索Bash特性，了解...
• Linux Bash Shell编程（九）：流程控制语句（上） 分支语句（if、case）   上一节中，我们学习了Bash中各种类型的条件判断语句。在Bash中，流程控制是条件判断语句的最终目的，条件判断语句是流程设计的基础条件...
• Linux Bash Shell编程（十）：流程控制语句（下） 循环语句（for while until） 上一节中，我们学习了流程控制语句中的分支语句。本节，我们一起来了解一下流程控制中的最后一个部分——循环语句，学会运用三个常见...
• Linux Bash Shell编程（七）：字符串截取与处理（cut、printf、awk、sed、sort）含示例   上一节中，我们了解了正则表达式的基本作用及其用法。本节我们来研究字符串截取、格式化输出、字符串处理命令 cut 命令...
• Linux Bash Shell编程（五）：变量（下）变量运算、内容替换、环境变量配置文件 上一节，我们对变量有了初步的了解，学会了变量的分类以及各种变量的基本操作和作用。本节我们来了解以下变量运算和运算符、变量测试...
•   上一节中，我们了解了Bash Shell中的变量计算、变量内容替换和环境变量配置文件相关内容。在了解了变量及其相关运算/操作后，本节开始，我们将一起了解Shell中的字符串处理方面内容，由于Bash的部分命令支持正则...

...