意外的行为

时间:2013-11-26 18:20:17

标签: bash

脚本:

#!/bin/bash

IFS=','
i=0

for j in `cat database | head -n 1`; do
   variables[$i]=$j
   i=`expr $i + 1`
done

k=0

for l in `cat database | tail -n $(expr $(cat database | wc -l) - 1)`; do
   echo -n $k

   k=`expr $k + 1`

   if [ $k -eq 3 ]; then
      k=0
   fi
done

输入文件

a,b,c
d,e,f
g,e,f

输出

01201

预期输出

012012

问题是为什么跳过最后的回声?这很奇怪,因为如果我将$ k更改为$ l,则echo将运行6次。

2 个答案:

答案 0 :(得分:2)

<强>更新

@ thom的分析是正确的。您可以通过将IFS=','更改为IFS=$',\n'来解决问题。

我在下面的原始陈述可能具有普遍意义,但不解决具体问题 如果意外的shell扩展是一个问题,这里是如何重写循环(假设首先将所有内容读入数组变量是实用的):

IFS=$',\n' read -d '' -r -a fields < <(echo $'*,b,c\nd,e,f\ng,h,i')
for field in "${fields[@]}"; do
  # $field is '*' in 1st iteration, then 'b', 'c', 'd',...
done

原始陈述

只是一些一般性的指示:

  • 您应该使用while循环而不是for来读取命令输出 - 请参阅http://mywiki.wooledge.org/BashFAQ/001;缺点:使用for,输入行可以进行各种shell扩展。

  • 缺少迭代通常源于最后一个输入行缺少终止\n(或$IFS中定义的分隔符)。使用while循环,您可以使用以下方法解决此问题:while read -r line || [[ -n $line ]]; do …

例如,您的第二个for循环可以重写为(使用进程替换作为输入以避免创建具有单独变量范围的子shell):

while read -r l || [[ -n $l ]]; do …; done < <(cat database | tail -n $(expr $(cat database | wc -l) - 1))

最后,您可以从使用现代基础知识中受益:例如,

k=`expr $k + 1`

可以更简洁地重写为(( ++k ))(也会更快地运行)。

答案 1 :(得分:2)

您的代码在每个读取变量之后都需要逗号,但您只能这样:

a,b,c
d,e,f
g,e,f

而不是:

a,b,c,
d,e,f,
g,e,f,

所以它写着:

d,e,f'\n'g,e,f 

并且等于5个值,而不是6个