linux shell中for循环,如何读取整一行
在处理一个多行数据的过程中,使用for循环去读取每行数据,结果发现输出是
[Sam@localhost 20220927-temp]$ more temp.list
aaa bbb ccc
ddd eee fff
ggg hhh iii
[Sam@localhost 20220927-BA]$ for i in `cat temp.list`;do echo $i;done
shell中for循环的默认分隔符是:空格、tab、\n
一、若shell for 循环以\n作为分隔符,输出整行
#! /bin/bash
IFS=$'\n'
for i in `cat emp.list`
echo $i
运行时使用./aa.sh 或者bash aa.sh。 不能使用sh aa.sh。
IFS="\n" # 将字符n作为IFS的换行符。
IFS=$"\n" # 这里\n确实通过$转化为了换行符,但仅当被解释时(或被执行时)才被转化为换行符;第一个和第二个是等价的
IFS=$'\n' # 这才是真正的换行符。
#! /bin/bash
while read i
echo $i
done <temp.list
#! /bin/bash
cat temp.list |while read i
echo $i
$ bash aa.sh
aaa bbb ccc
ddd eee fff
ggg hhh iii
二、若shell循环,读取每行第二列,列之间以tab分隔
开始时使用read 定义tab键的方式不成功
$ while read i; do a=`echo $i|cut -f2 -d ' '`; echo $a;done <temp.list
aaa bbb ccc
ddd eee fff
ggg hhh iii
$ while read i; do a=`echo $i|cut -f2 -d$'\t'`; echo $a;done <temp.list
aaa bbb ccc
ddd eee fff
ggg hhh iii
转换为"$i" 则可成功,是因为echo $i会将默认tab或者空格作为分隔符的默认输出为空格,若管道后的命令的分隔符为\t,则不会按要求分割。
$ while read i; do a=`echo "$i"|cut -f2 -d ' '`; echo $a;done <temp.list
$ while read i; do a=`echo "$i"|cut -f2 -d $'\t'`; echo $a;done <temp.list
cut 的tab分隔符有两种方式:(1)先ctrl+v,然后按tab键,记得用单引号引起来;(2)使用$'\t'。
可以使用将行存入数组的方式调取数组的第二个元素,但要确保每列使用同样的分隔符,若既有空格又有tab键分隔符,则会出现混乱
$ while read line;do a=($line); echo ${a[1]};done <temp.list
while read line; do a=${line#* };b=${a%% *};echo $a,$b;done <temp1.list
bbb ccc,bbb
eee fff,eee
hhh iii,hhh
hanna2 hanna3,hanna2
#前两列为a变量,后一列为b变量。此处是按照tab键分隔。
##################################################################################################
环境变量IFS,成为内部字段分隔符(internal field seperator),定义了bash shell 用作字段分隔符的一系列字符。默认情况下,bash shell会将下列字符当作字段分隔符
制表符 tab键
换行符 \n
可使用以下命令查看当前默认的IFS
$ echo "$IFS" | od -b
0000000 040 011 012 012
0000004
$ set |grep IFS
IFS=$' \t\n'
直接输出IFS是看不到的,把它转化为二进制就可以看到了,"040"是空格,"011"是Tab,"012"是换行符"\n" 。最后一个 012 是因为 echo 默认是会换行的。
若单行数据中有空格时,使用for循环读取每一行,由于空格为默认的字段分隔符,bash shell 遇到空格,就认为读取到一个新的字段,会出现问题。此时需要在shell脚本中临时改变环境变量IFS的值来限制被bash shell当作字符段的字符,如修改为IFS=$'\n'
,IFS=$'\t'
。
但是修改完IFS后,如何恢复IFS默认值?
答: 方法一:简单粗暴,直接关闭当前终端。(经测试若修改只影响当前终端窗口)
方法二:可以在修改IFS之前保存原来的IFS值,之后在恢复它,以防忘记,后续出现奇奇怪怪的显示。如下所示:
IFS_old=$IFS
IFS=$'\n'
#在接下来的代码中使用新的IFS
#code
#使用完毕后恢复IFS原来的值
IFS=$IFS_old
答:方式三:在终端输入IFS=$' \t\n'
,即将是恢复为空格、tab键、和换行符作为分隔符。
##################################################################################################
while read line是一次性将一行的文件信息读入并赋值给变量line。当文件中有多行文字,在while循环中再一次调用read语句,就会读取到下一条记录。而$line中的最后一行读完,无法获取下一行记录,从而退出while循环。
for是每次读取文件中一个以空格为分隔符的字符串。