CSH脚本遍历grep结果异常:输出不符且变量报错
解决CSH脚本遍历grep输出行的问题
问题场景
现有CSH脚本用于遍历grep匹配到的行,每行包含两个单词(如apple good),并对对应子目录进行操作。脚本如下:
cat > fridge << BYE apple good banana bad cherry good BYE foreach ln (`grep good fridge`) echo "line is= ${ln}" set fruit= `echo ${ln} | cut -d' ' -f1` set status= `echo ${ln} | cut -d' ' -f2` echo "fruit= ${fruit} is ${status}" pushd ${fruit}_dir #<do something> popd end
执行后仅输出line is= apple,随后报错set: Variable name must begin with a letter.,无法达到预期输出。
问题原因
CSH的foreach默认会将命令替换(`...`)的输出按空格、制表符、换行符分割成单个元素遍历,而非按行。因此grep good fridge输出的两行apple good和cherry good会被拆成四个独立元素:apple、good、cherry、good。
当遍历到第二个元素good时,set status= echo ${ln} | cut -d' ' -f2``中,cut无法提取到第二字段,输出为空,导致set status=后无合法变量值,触发报错。
解决方案
要让foreach按行遍历,需修改IFS(内部字段分隔符),仅保留换行符作为分隔符。修改后的脚本如下:
cat > fridge << BYE apple good banana bad cherry good BYE # 保存原始IFS,遍历后恢复 set oldifs="$IFS" set IFS=" " foreach ln (`grep good fridge`) echo "line is= ${ln}" # 用CSH内置数组拆分替代外部cut命令 set parts=($ln) set fruit="$parts[1]" set status="$parts[2]" echo "fruit= ${fruit} is ${status}" pushd ${fruit}_dir # 示例操作:打印当前处理的水果名称 echo "Some stuff from do something with ${fruit}" popd end # 恢复原始IFS,避免影响后续逻辑 set IFS="$oldifs"
关键改进点
- 修改IFS:将IFS设置为仅换行符,确保
foreach按行读取grep输出。 - 内置字符串拆分:用CSH原生的数组拆分
set parts=($ln)替代外部cut命令,减少进程开销且更可靠。 - 恢复IFS:遍历完成后还原原始IFS,防止对脚本后续逻辑造成意外影响。
预期输出
line is= apple good fruit= apple is good Some stuff from do something with apple line is= cherry good fruit= cherry is good Some stuff from do something with cherry
内容的提问来源于stack exchange,提问作者Gert Gottschalk
相关产品推荐
相关产品推荐

