遇到shell重定向的一个奇怪问题:'消失'的标准输入!
需求:
把找到的文件逐行输出,然后用rm在许可的情况下删除
前置准备:
$ls rm.sh test1 test2 test3 test4 test5 test6
$cat rm.sh #! /bin/bash while read fileinfo do rm -iv $fileinfo done< <( find . -name 'test*' -print )
第一次执行结果:
$bash rm.sh rm:是否删除普通文件“./test2”?
出现的问题:
虽然rm显示了询问信息,却并不关心我输入的是什么(就没给我机会),也没有删除文件
第一次结果分析:
rm -iv需要从标准输入中获取允许,但标准输入已经被重定向为’done< <( find $path -type f -print )‘,所以rm只能从这获取输入了,也造成了这一次执行的令就无效了,然后read和rm就不断地逐次消耗掉输入的行,也就什么都没做了;
第二次前置准备:
$ls rm2.sh test1 test2
$cat test1 test1 test2 test3 test4 test5 test6
程序解释:
当每次read到的内容不为空就输出到屏幕,count统计的是尝试的删除次数
$cat rm2.sh #! /bin/bash count=0 while read info do if [ ! -z info ] then echo $info:not null fi rm -iv test2 let count++ echo $count done< test1
第二次执行结果:
$bash rm2.sh test1:not_null rm:是否删除普通文件 “test2”?1 test3:not_null rm:是否删除普通文件 “test2”?2 test5:not_null rm:是否删除普通文件 “test2”?3
验证分析:
符合第一次结果分析的猜测;
解决方案:
将原标准输入(键盘输入)存放在新的文件描述符中,并在rm中将新的文件描述符作为它的输入
修正后的程序:
$cat rm3.sh #! /bin/bash exec 3<&0 while read fileinfo do rm -iv $fileinfo <&3 done< <( find . -type f -print )
顺带一提:
'done< <( find . -type f -print )'有两个‘<’的原因:
第一步:‘<( find . -type f -print )’相当于将子shell中的结果输出到一个临时文件
第二步:‘done< temp_file’从临时文件中获取输入