linux\bash shell for命令\循环

内容来自《Linux命令行与shell脚本编程大全.第3版 (布鲁姆,布雷斯纳汉)》
for命令

下面是基本格式:

for var in list     # 或者把do也写在这一行:for var in list; do
do
    commands
done

例如,读取列表:

for test in Aliabma Alska Arizona Arkansas California Colorado
do
        echo The next state is $test
done

结果输出:

The next state is Aliabma
The next state is Alska
The next state is Arizona
The next state is Arkansas
The next state is California
The next state is Colorado

(test也是一个命令,但$test仍可作为变量名使用)

在最后一次迭代后,$test变量的值会在shell脚本的剩余 部分一直保持有效。它会一直保持最后一次迭代的值(除非你修改了它)。

从变量读取列表
for命令用空格来划分列表中的每个值。如果在单独的数据值中有 空格,就必须用双引号将这些值圈起来。有单引号的,也可以使用转义字符(反斜线)来将单引号转义。

list="Alabama Alaska Arizona Arkansas Colorado"
list=$list" Connecticut"
for state in $list
do
    echo "Have you ever visited $state?"
done 

(注意,代码还是用了另一个赋值语句向$list 变量包含的已有列表中添加(或者说是拼接)了一个值。这是向变量中存储的已有文本字符串尾部添加文本的一个常用方法。)

结果输出:

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?

从命令读取值
生成列表中所需值的另外一个途径就是使用命令的输出。可以用命令替换来执行任何能产生 输出的命令,然后在for命令中使用该命令的输出。

file="states"
for state in $(cat $file)
do
 echo "Visit beautiful $state"
done
$ cat states
Alabama
Alaska
Arizona
Arkansas
Colorado
Connecticut
Delaware
Florida
Georgia

(上面的例子将文件名赋给变量,文件名中没有加入路径。这要求文件和脚本位于同 一个目录中。如果不是的话,你需要使用全路径名(不管是绝对路径还是相对路径)来引用文件位置。这个例子在命令替换中使用了cat命令来输出文件states的内容。)

结果输出:

Visit beautiful Alabama
Visit beautiful Alaska
Visit beautiful Arizona
Visit beautiful Arkansas
Visit beautiful Colorado
Visit beautiful Connecticut
Visit beautiful Delaware
Visit beautiful Florida 

你会注意到states文件中每一行有一个州,而不是通过空格分隔的。for命令仍然以每次一行的方式遍历了cat命令的输出。但这并没有解决数据中有空格的问题。如果你列出了一个名字中有空格的州,for命令仍然会将每个单词当作单独的值。

造成这个问题的原因是特殊的环境变量IFS,叫作内部字段分隔符(internal field separator)。 IFS环境变量定义了bash shell用作字段分隔符的一系列字符。默认情况下,bash shell会将下列字 符当作字段分隔符: 空格 制表符 换行符

如果bash shell在数据中看到了这些字符中的任意一个,它就会假定这表明了列表中一个新数据字段的开始。在处理可能含有空格的数据(比如文件名)时,这会非常麻烦,就像你在上一个脚本示例中看到的。

要解决这个问题,可以在shell脚本中临时更改IFS环境变量的值来限制被bash shell当作字段 分隔符的字符。例如,如果你想修改IFS的值,使其只能识别换行符,那就必须这么做:

IFS=$'\n' 

将这个语句加入到脚本中,告诉bash shell在数据值中忽略空格和制表符。

比如:

file="states"
IFS=$'\n'
for state in $(cat $file)
do
    echo "Visit beautiful $state"
done 

在state文件末尾添加三个州名:

New York
New Hampshire
North Carolina

结果输出:

Visit beautiful Alabama
Visit beautiful Alaska
Visit beautiful Arizona
Visit beautiful Arkansas
Visit beautiful Colorado
Visit beautiful Connecticut
Visit beautiful Delaware
Visit beautiful Florida
Visit beautiful Georgia
Visit beautiful New York
Visit beautiful New Hampshire
Visit beautiful North Carolina

警告:

在处理代码量较大的脚本时,可能在一个地方需要修改IFS的值,然后忽略这次修改,在
脚本的其他地方继续沿用IFS的默认值。一个可参考的安全实践是在改变IFS之前保存原
来的IFS值,之后再恢复它。
这种技术可以这样实现:
 IFS.OLD=$IFS
 IFS=$'\n'
 <在代码中使用新的IFS值>
 IFS=$IFS.OLD
这就保证了在脚本的后续操作中使用的是IFS的默认值。

还有其他一些IFS环境变量的绝妙用法。假定你要遍历一个文件中用冒号分隔的值(比如在 /etc/passwd文件中)。你要做的就是将IFS的值设为冒号。

IFS=: 

如果要指定多个IFS字符,只要将它们在赋值行串起来就行。

IFS=$'\n':;" 

这个赋值会将换行符、冒号、分号和双引号作为字段分隔符。如何使用IFS字符解析数据没 有任何限制。

用通配符读取目录

最后,可以用for命令来自动遍历目录中的文件。进行此操作时,必须在文件名或路径名中使用通配符。它会强制shell使用文件扩展匹配。如果不知道所有的文件名,这个特性在处理目录中的文件时就非常好用。

在过滤器中使用星号和问号被称为文件扩展匹配(file globbing),指的是使用通配符进行模 式匹配的过程。

如:

ls -l my_s*t

结果输出:

-rw-rw-r-- 1 christine christine 0 May 21 13:25 my_scrapt
-rwxrw-r-- 1 christine christine 54 May 21 11:26 my_script

例如:

for file in /home/rich/.b* /home/rich/badtest
do
 if [ -d "$file" ]
 then
     echo "$file is a directory"
 elif [ -f "$file" ]
 then
     echo "$file is a file"
 else
     echo "$file doesn't exist"
 fi
done 

(for语句首先使用了文件扩展匹配来遍历由通配符生成的文件列表,然后它会遍历列表中的下一个文件。可以将任意多的通配符放进列表中。)

结果输出:

/home/rich/.backup.timestamp is a file
/home/rich/.bash_history is a file
/home/rich/.bash_logout is a file
/home/rich/.bash_profile is a file
/home/rich/.bashrc is a file
/home/rich/badtest doesn't exist

例子中进行了文件比较。test命令允许你测试Linux文件系统上文件和目录的状态。使用中括号可以替代test命令。

在这里插入图片描述

注意,你可以在数据列表中放入任何东西。即使文件或目录不存在,for语句也会尝试处
理列表中的内容。在处理文件或目录时,这可能会是个问题。你无法知道你正在尝试遍
历的目录是否存在:在处理之前测试一下文件或目录总是好的。

还可以使用C 语言风格的for语句。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值