-
#!/bin/bash
-
-
echo "#####first #####"
-
while read line1
-
do
-
echo $line1
-
done < $1
-
-
echo "##### second #####"
-
cat $1 | while read line2
-
do
-
echo $line2
-
done
-
-
echo "##### third#####"
-
for line3 in $(<$1)
-
do
-
echo $line3
-
done
使用for读取时,自动按空格作为间隔符。
如果输入文本每行中没有空格,则line在输入文本中按换行符分隔符循环取值.
如果输入文本中包括空格或制表符,则不是换行读取,line在输入文本中按空格分隔符或制表符或换行符特环取值.
可以通过把IFS设置为换行符来达到逐行读取的功能.
[cpp] view plaincopy
-
IFS=$'\n'
-
-
echo "##### 方法 3 #####"
-
for line3 in $(<$1)
-
do
-
echo $line3
-
done
-
网上有很多 shell script 读文本文件的例子,但是都没有讲出故事的全部,只说了一半。举个例子,比如从一个 testfile 文件中读取如下格式的文本行:
$ vi testfile ls -a -l /bin | sort ls -a -l /bin | sort | wc ls -a -l | grep sh | wc ls -a -l ls -a -l | sort | wc
最常见的一个 line by line 读取文件内容的例子就是:
$ vi readfile #!/bin/sh testfile=$1 while read -r line do echo $line done < $testfile $ chmod +x readfile $ ./readfile testfile ls -a -l /bin | sort ls -a -l /bin | sort | wc ls -a -l | grep sh | wc ls -a -l ls -a -l | sort | wc
这个例子的问题是读取文本行后,文本格式发生了变化,和原来 testfile 文件的内容不完全一致,空格字符自动被删除了一些。为什么会这样呢?因为 IFS,如果在 shell script 里没有明确指定 IFS 的话,IFS 会默认用来分割空格、制表、换行等,所以上面文本行里多余的空格和换行都被自动缩进了。
如果想要输出 testfile 文件原有的格式,把每行(作为整体)原封不动的打印出来怎么办?这时需要指定 IFS 变量,告诉 shell 以 "行" 为单位读取。
$ vi readfile #!/bin/sh IFS=" " testfile=$1 while read -r line do echo $line done < $testfile $ ./readfile testfile ls -a -l /bin | sort ls -a -l /bin | sort | wc ls -a -l | grep sh | wc ls -a -l ls -a -l | sort | wc
上面两种方法的输出不是差不多吗,有什么关系呢,第一种还美观一些?关系重大,VPSee 昨天写了一个模拟 shell 的 C 程序,然后又写了一个 shell script 来测试这个 C 程序,这个 script 需要从上面的 testfile 里读取完整一行传给 C 程序,如果按照上面的两种方法会得到两种不同的输入格式,意义完全不同:
$./mypipe ls -a -l | sort | wc
$./mypipe "ls -a -l | sort | wc "
显然我要的是第2种输入,把 "ls -a -l | sort | wc " 作为整体传给我的 mypipe,来测试我的 mypipe 能不能正确识别出字符串里面的各种命令。
如果不用 IFS 的话,还有一种方法可以得到上面第二种方法的效果:
#!/bin/sh testfile=$1 x=`wc -l $testfile |awk '{print $1}'` i=1 while [ $i -le $x ] do echo "`head -$i $testfile | tail -1`" i=`expr $i + 1` done
用Bash一行一行的读取文件
发布时间:2011/07/22 / 作者: 周亮
将配置信息写在文本文件中,使用bash一行一行的读取文本文件,然后执行相应的操作,是非常常见的需求,本文使用了shell脚本的while循环和read命令非常简单的达到了目的
其实我的目标是用git下载Eclipse的源代码,Eclipse的源代码是用CVS管理的,会自动同步到Eclipse的git仓库,仓库地址为:http://dev.eclipse.org/git/index.html。
我复制了git仓库的url到一个文本文件urls中,一行一个:
http://dev.eclipse.org/git/org.eclipse.pde/apitools.githttp://dev.eclipse.org/git/org.eclipse.pde/build.githttp://dev.eclipse.org/git/org.eclipse.pde/doc.githttp://dev.eclipse.org/git/org.eclipse.pde/ds.githttp://dev.eclipse.org/git/org.eclipse.pde/org.eclipse.pde.releng.githttp://dev.eclipse.org/git/org.eclipse.pde/ua.githttp://dev.eclipse.org/git/org.eclipse.pde/ui.githttp://dev.eclipse.org/git/org.eclipse.pde/visualization.git
然后想办法读取这个文本文件,执行git clone命令:
cat urls | while read line; do git clone ${line}; done
上面的命令其实是四条命令,
-
cat urls是第一条,将文本文件中的内容输出到标注输出,urls是文本文件名称;
-
while read line是第二条,循环读取标准输入,存放到line变量中,read命令请见参考1;
-
do git clone ${line}是第三条,克隆git仓库到本地文件夹中,git默认为将“xxx.git”中的“.git”去掉,取“xxx”作为克隆项目的目录名称,关于git请见参考3;
-
done是第四条,标示while语句的结束
如果两条命令写在同一行则需要用;号隔开,一行只写一条命令就不需要写;号了。while后面的子命令通常是测试命令,在本例中,读取文件结束,read返回0,循环结束。关于shell请见参考2。
ls -d */ | while read line; do cd ${line}; git pull origin master; cd ..; done
在克隆了git仓库后,还需要执行“git pull”命令更新仓库,仿照上例即可写出上面的代码。
"ls -d */"输出当前文件夹下的文件夹名称,虽然在控制台里面看起来输出在一行,但是实际上用下面的命令就会发现其实每个文件夹名称都是在单独的一行的,关于wc请见参考4。
ls -d */ | wc -l