Linux下Bash Shell编程
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在做这样或那样的事情时真的很没效率”。请写(信息页)报告实际的错误。
·
·If this page seems too sketchy andelementary for your taste, you can choose from among the more advancedresources in .
·如果本页的信息看起来太简单,太初级的话,可以从中选择更高级的资源。
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脚本的方式。
oIn theinteractive mode, the usertypes a single command (or a short string of commands) and the result isprinted out.
o在交互模式中,用户输入单个命令(或者短的命令字符串),然后结果被输出。
oInshell 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脚本方式运行。
oIt 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
/home/username
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脚本文件必须满足一些条件:
oThe 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可执行文件加载的路径并替换上面例子的路径。下面是一种确定方法:
oThe file must be made executable bychanging its permission bits. An example:
oBash 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:
oIf you write "test &&command", the command will only be executed if the testsucceeds.
oIf 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
menu of choices:
·
·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:"
·read 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:
oOperator "#" means "deletefrom the left, to the first case of what follows."
o
o$ x="This is my test string."
o$ echo ${x#* }
o
ois my test string.
o
o
oOperator "##" means "deletefrom the left, to the last case of what follows."
o
o$ x="This is my test string."
o$ echo ${x##* }
o
ostring.
o
o
oOperator "%" means "deletefrom the right, to the first case of what follows."
o
o$ x="This is my test string."
o$ echo ${x% *}
o
oThis is my test
o
o
oOperator "%%" means "deletefrom the right, to the last case of what follows."
o
o$ x="This is my test string."
o$ echo ${x%% *}
o
oThis
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 BaseAdventures in Ray TracingBash Script BeautifierBash Shell Programming in LinuxConsistent Network Device NamingDictionary access under LinuxDictionary front end using PHPInstalling Linux on a Dell XPS LaptopMobile Internet Access Using LinuxModelinesNetworkManagerNokiaNotes and Fixes for Fedora 17Running Fedora Linux on Dell LaptopsSecure Shell Fun and Games
Share This Page