也可以将do语句和for语句放在同一行,但必须用分号将其同列表中的值分 开:for var in list; do
1.1 读取列表中的值
for命令最基本的用法就是遍历for命令自身所定义的一系列值。案例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
$ cat test1 #!/bin/bash # basic for command for test in Alabama Alaska Arizona Arkansas California Colorado do echo The next state is $test done
$ ./test1 The next state is Alabama The next state is Alaska The next state is Arizona The next state is Arkansas The next state is California The next state is Colorado $
1.2 读取列表中复杂值
列表中可能有像单引号等不好读取的值,需要我们对此进行转置
使用转义字符(反斜线)来将单引号转义;
使用双引号来定义用到单引号的值。
如果在单独的数据值中有空格,就必须用双引号将这些值圈起来。
案例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
$ cat test2 #!/bin/bash # another example of how not to use the for command fortestin I don\'t know if"this'll" work do echo"word:$test" done
$ cat test4 #!/bin/bash # using a variable to hold the list list="Alabama Alaska Arizona Arkansas Colorado" list=$list" Connecticut" for state in$list do echo"Have you ever visited $state?" done
$ ./test4 Have you ever visited Alabama? Have you ever visited Alaska? Have you ever visited Arizona? Have you ever visited Arkansas? Have you ever visited Colorado? Have you ever visited Connecticut?
$ cat test6 #!/bin/bash # iterate through all the files in a directory forfile in /home/rich/test/* do if [ -d "$file" ] then echo "$file is a directory" elif [ -f "$file" ] then echo "$file is a file" fi done
$ ./test6 /home/rich/test/dir1 is a directory /home/rich/test/myprog.c is a file /home/rich/test/myprog is a file /home/rich/test/myscript is a file /home/rich/test/newdir is a directory /home/rich/test/newfile is a file /home/rich/test/newfile2 is a file /home/rich/test/testdir is a directory /home/rich/test/testing is a file /home/rich/test/testprog is a file /home/rich/test/testprog.c is a file
注意,我们在这个例子的if语句中做了一些不同的处理:
if [ -d "$file" ] 在Linux中,目录名和文件名中包含空格当然是合法的。要适应这种情况,应该将$file变 量用双引号圈起来。如果不这么做,遇到含有空格的目录名或文件名时就会有错误产生。
1 2
>./test6: line 6: [: too many arguments >./test6: line 9: [: too many arguments
#!/bin/bash # changing the IFS value IFS.OLD=$IFS IFS=$'\n' for entry in $(cat /etc/passwd) do echo"Values in $entry –" IFS=: for value in$entry do echo" $value" done done $
13.9.1 查找可执行文件 当你从命令行中运行一个程序的时候,Linux系统会搜索一系列目录来查找对应的文件。这 些目录被定义在环境变量PATH中。如果你想找出系统中有哪些可执行文件可供使用,只需要扫 描PATH环境变量中所有的目录就行了。如果要徒手查找的话,就得花点时间了。不过我们可以 编写一个小小的脚本,轻而易举地搞定这件事。 首先是创建一个for循环,对环境变量PATH中的目录进行迭代。处理的时候别忘了设置IFS 分隔符。 IFS=: for folder in$PATH do 现在你已经将各个目录存放在了变量$folder中,可以使用另一个for循环来迭代特定目录 中的所有文件。 for file in$folder/* do 最后一步是检查各个文件是否具有可执行权限,你可以使用if-then测试功能来实现。 if [ -x $file ] then echo" $file" fi 好了,搞定了!将这些代码片段组合成脚本就行了。 $ cat test25 #!/bin/bash # finding files in the PATH IFS=: for folder in$PATH do echo"$folder:" for file in$folder/* do if [ -x $file ] then echo" $file" fi done done $ 运行这段代码时,你会得到一个可以在命令行中使用的可执行文件的列表。 $ ./test25 | more /usr/local/bin: /usr/bin: /usr/bin/Mail /usr/bin/Thunar /usr/bin/X /usr/bin/Xorg /usr/bin/[ /usr/bin/a2p /usr/bin/abiword /usr/bin/ac /usr/bin/activation-client /usr/bin/addr2line ... 输出显示了在环境变量PATH所包含的所有目录中找到的全部可执行文件,数量真是不少!
13.9.2 创建多个用户账户 shell脚本的目标是让系统管理员过得更轻松。如果你碰巧工作在一个拥有大量用户的环境 中,最烦人的工作之一就是创建新用户账户。好在可以使用while循环来降低工作的难度。 你不用为每个需要创建的新用户账户手动输入useradd命令,而是可以将需要添加的新用户 账户放在一个文本文件中,然后创建一个简单的脚本进行处理。这个文本文件的格式如下: userid,user name 第一个条目是你为新用户账户所选用的用户ID。第二个条目是用户的全名。两个值之间使用 逗号分隔,这样就形成了一种名为逗号分隔值的文件格式(或者是.csv)。这种文件格式在电子表 格中极其常见,所以你可以轻松地在电子表格程序中创建用户账户列表,然后将其保存成.csv格 式,以备shell脚本读取及处理。 要读取文件中的数据,得用上一点shell脚本编程技巧。我们将IFS分隔符设置成逗号,并将 其放入while语句的条件测试部分。然后使用read命令读取文件中的各行。实现代码如下: while IFS=’,’ read –r userid name read命令会自动读取.csv文本文件的下一行内容,所以不需要专门再写一个循环来处理。当 read命令返回FALSE时(也就是读取完整个文件时),while命令就会退出。妙极了! 要想把数据从文件中送入while命令,只需在while命令尾部使用一个重定向符就可以了。 将各部分处理过程写成脚本如下。 $ cat test26 #!/bin/bash # process new user accounts input="users.csv" while IFS=','read -r userid name do echo"adding $userid" useradd -c "$name" -m $userid done < "$input" $ $input变量指向数据文件,并且该变量被作为while命令的重定向数据。users.csv文件内容 如下。 $ cat users.csv rich,Richard Blum christine,Christine Bresnahan barbara,Barbara Blum tim,Timothy Bresnahan $ 必须作为root用户才能运行这个脚本,因为useradd命令需要root权限。 # ./test26 adding rich adding christine adding barbara adding tim # 来看一眼/etc/passwd文件,你会发现账户已经创建好了。 # tail /etc/passwd rich:x:1001:1001:Richard Blum:/home/rich:/bin/bash christine:x:1002:1002:Christine Bresnahan:/home/christine:/bin/bash barbara:x:1003:1003:Barbara Blum:/home/barbara:/bin/bash tim:x:1004:1004:Timothy Bresnahan:/home/tim:/bin/bash #