在shell程序中引入参数,shell程序就会灵活很多。本文首先简单介绍参数传递中的一些基本知识点,再通过一个通讯录的举例来加深对shell编程中参数传递的理解。
1. 参数的引用
当运行shell程序时,shell会自动将命令行中第一个参数保存在变量1中,第二个参数保存在变量2中,依次类推。因此,当需要在shell程序中使用这些参数时,便可以通过$1和$2这样的方法来引用。比如:
edsionte@edsionte-laptop:~/shelltest$ cat myargs
echo "\"$1\" \"$2\" was passed"
edsionte@edsionte-laptop:~/shelltest$ ./myargs edsionte wu
"edsionte" "wu" was passed
edsionte@edsionte-laptop:~/shelltest$ ./myargs edsionte
"edsionte" "" was passed
edsionte@edsionte-laptop:~/shelltest$ ./myargs edsionte wu me
"edsionte" "wu" was passed
通过上述举例可以看到,命令行中的第n个参数会自动传递给相应的特殊变量n。通过$n就可以在shell程序中对其进行引用;当引用未赋值的特殊变量时,其结果将会显示空。
2. #变量
每当shell程序运行时,特殊变量#中就会保存此次shell程序中键入的参数个数。比如:
echo "There are $# arguments passed"
echo "\"$1\" \"$2\" was passed"
edsionte@edsionte-laptop:~/shelltest$ ./myargs edsionte
There are 1 arguments passed
"edsionte" "" was passed
命令行中的参数是以空格作为间隔。因此,下面这种结果也很合理:
edsionte@edsionte-laptop:~/shelltest$ ./myargs "edsionte wu"
There are 1 arguments passed
"edsionte wu" "" was passed
edsionte@edsionte-laptop:~/shelltest$ name="edsionte wu"
edsionte@edsionte-laptop:~/shelltest$ ./myargs $name
There are 2 arguments passed
"edsionte" "wu" was passed
3. *变量
特殊变量*中会保存shell程序运行时用户键入的所有参数。在参数不确定或参数数目易变时,该变量就很有用。
edsionte@edsionte-laptop:~/shelltest$ cat myargs
echo "There are $# arguments passed"
echo "\"$*\" was passed"
edsionte@edsionte-laptop:~/shelltest$ ./myargs edsionte wu is me
There are 4 arguments passed
"edsionte wu is me" was passed
edsionte@edsionte-laptop:~/shelltest$ ./myargs edsionte wu
There are 2 arguments passed
"edsionte wu" was passed
4. 通信录举例
查找用户
现在需要通过用户姓名从通信录info中查找一个用户的个人信息。我们通过编写shell程序lu来实现这个功能。最简单的程序为:
edsionte@edsionte-laptop:~/shelltest$ cat info
edsionte wu:male:xian:18717375182
sen wang:female:hanzhong:15678675545
ting li:male:guangzhou:15784859345
jedsionte:male:xian:13556567884
edison:male:hongkong:1384742488
yun zhang:female:beijing:18654737473
edsionte@edsionte-laptop:~/shelltest$ cat lu
# look someone up in the info book
grep $1 info
edsionte@edsionte-laptop:~/shelltest$ ./lu edsionte
edsionte wu:male:xian:18717375182
jedsionte:male:xian:13556567884
这个结果似乎并不令人满意,因为我们想找用户名为edsionte的用户。不过这个问题很好解决,我们可以这样改进程序:
edsionte@edsionte-laptop:~/shelltest$ cat lu
# look someone up in the info book
grep ^$1 info
edsionte@edsionte-laptop:~/shelltest$ ./lu edsionte
edsionte wu:male:xian:18717375182
如果我们想通过全名edsionte wu来查找用户信息,就应该用双引号将全名作为一个整体引入其中。这样看似很完美,可是结果却不尽人意:
edsionte@edsionte-laptop:~/shelltest$ ./lu "edsionte wu"
grep: wu: 没有那个文件或目录
info:edsionte wu:male:xian:18717375182
这是因为虽然edsionte wu作为一个参数传递给特殊变量1,但是shell将其替换后,grep命令并不认为edsionte wu是一个参数,而是将wu作为目标文件之一。为了避免这种情况,我们应该这样改进程序:
edsionte@edsionte-laptop:~/shelltest$ cat lu
# look someone up in the info book
grep "^$1" info
edsionte@edsionte-laptop:~/shelltest$ ./lu "edsionte wu"
edsionte wu:male:xian:18717375182
这样就可以满足我们要求了。但是,如果info中的信息如下所示,那么上述lu程序还是不算完美。比如:
edsionte@edsionte-laptop:~/shelltest$ cat info
edsionte wu:male:xian:18717375182
sen wang:female:hanzhong:15678675545
edsionte wuee:male:xian:18717375182
ting li:male:guangzhou:15784859345
jedsionte:male:xian:13556567884
edison:male:hongkong:1384742488
yun zhang:female:beijing:18654737473
edsionte@edsionte-laptop:~/shelltest$ ./lu "edsionte wu"
edsionte wu:male:xian:18717375182
edsionte wuee:male:xian:18717375182
因此,我们也应该在参数的尾部也做一些“手脚”,使得grep命令只匹配我们所传递的参数:
edsionte@edsionte-laptop:~/shelltest$ cat lu
# look someone up in the info book
grep "^$1:" info
edsionte@edsionte-laptop:~/shelltest$ ./lu "edsionte wu"
edsionte wu:male:xian:18717375182
至此,查找程序完成。
添加用户
当向通讯录中增添新用户信息时,我们必须再编写一个add程序。增加用户程序很简单:
edsionte@edsionte-laptop:~/shelltest$ cat add
# add someone to the info book
echo "$1:$2:$3:$4" >> info
edsionte@edsionte-laptop:~/shelltest$ ./add elva female taibei 1335676567
edsionte@edsionte-laptop:~/shelltest$ ./lu elva
elva:female:taibei:1335676567
>>使得新的信息会追加到原文件的末尾。在上述命令的基础上,我们还可以再增加按姓名排序的功能:
edsionte@edsionte-laptop:~/shelltest$ cat add
# add someone to the info book
echo "$1:$2:$3:$4" >> info
sort -o info info
edsionte@edsionte-laptop:~/shelltest$ cat info
edison:male:hongkong:1384742488
edsionte wuee:male:xian:18717375182
edsionte wu:male:xian:18717375182
elva:female:taibei:1335676567
jedsionte:male:xian:13556567884
sen wang:female:hanzhong:15678675545
ting li:male:guangzhou:15784859345
yun zhang:female:beijing:18654737473
添加程序结束。
删除用户
有了上述两个程序的基础,删除用户程序则变得容易很多。首先通过sed命令将完全匹配给定人名的用户信息从info中删除;因为sed命令并不改变info文件本身的内容,因此需要将sed的输出结果暂存至缓冲区;最后通过mv命令替换文件名即可。
edsionte@edsionte-laptop:~/shelltest$ cat del
# delete the given user from info
sed "/^$1:/d" info > /tmp/info
mv /tmp/info ./info
edsionte@edsionte-laptop:~/shelltest$ ./del elva
edsionte@edsionte-laptop:~/shelltest$ cat info
edison:male:hongkong:1384742488
edsionte wuee:male:xian:18717375182
edsionte wu:male:xian:18717375182
jedsionte:male:xian:13556567884
sen wang:female:hanzhong:15678675545
ting li:male:guangzhou:15784859345
yun zhang:female:beijing:18654737473
随着对shell编程的深入理解,上述通讯录程序还可以不断完善。