2016-09-20 55 views
3

这是一个新的和更进一步的问题: Output the result of each loop in different columns从linux中的循环中抽取字符串中的特定字符

但是由于这是一个新问题,你不需要看链接中的问题,我会明确地澄清下面的新问题。

money.txt文件有两列:(名字和金钱)

Mary 13 
Lucy 8 
Jack 20 

range.txt文件中有三列:(水果,MIN_VALUE和MAX_VALUE)

apple 10 15 
banana 7 12 
orange 17 22 
blueberry 14 22 

我的目的是要测试是否有钱money.txt文件位于range.txt的min_value和max_value之间。如果是,则在range.txt中输出(max_value - moneyfruit的第012个字符,如果不是,则输出"x"

例如,Mary处于money.txt1313apple的MIN_VALUE和MAX_VALUE内,并且max_value - money值为15 - 13 = 2,所以应该打印出的apple的第2个字符,即p

预期的结果是:(第4列是玛丽,第5栏是露西,6列是杰克)

apple 10 15 p x x 
banana 7 12 x a x 
orange 17 22 x x r 
blueberry 14 22 x x l 

随着@ocurran的帮助下,我想:

# load prices by index to maintain read order 
awk 'FNR == NR { 
    money[names++]=$2 
    next 
} 
# save max index to avoid using non-standard length(array) 
END { 
    names=NR 
} 
{ 
l = $1 " " $2 " " $3 
for (i=0; i < names; i++) { 
    if ($2 <= money[i] && $3 >= money[i]) { 
      fruit=$1 
      fruitcharacter=${fruit:($3-money[i]-1):1} 
      l = l " " $fruitcharacter 
    } else { 
      l = l " x" 
    } 
} 
print l 
}' money.txt range.txt 

结果表明:

awk: line 14: syntax error at or near { 
awk: line 16: syntax error at or near else 
awk: line 19: syntax error at or near } 

似乎fruitcharacter=${fruit:($3-money[i]-1):1}不能工作。但据我所知,我们可以使用${string: index: length}来提取字符串的字符,我不知道为什么它不能在这种情况下工作。你能帮我解决这个问题吗?谢谢。

+1

从awk脚本的开头开始计数14行,并得到'fruitcharacter = $ {fruit:($ 3-money [i] -1):1}这句话,这对awk来说是句法无稽之谈,因此语法错误输出消息。你说“据我所知,我们可以使用'$ {string:index:length}'来提取字符串的字符”,但这绝对不是真的(提示:** awk不是shell!**)。阅读Arnold Robbins编写的“有效的Awk编程”第4版。 –

+1

@EdMorton谢谢!我确实混合了一些概念。 – lightsnail

回答

4
$ cat tst.awk 
NR==FNR { money[NR]=$2; next } 
{ 
    out = $0 
    for (i=1; i in money; i++) { 
     out = out OFS ((money[i]>=$2) && (money[i]<=$3) ? substr($1,2,1) : "x") 
    } 
    print out 
} 

$ awk -f tst.awk money.txt range.txt 
apple 10 15 p x x 
banana 7 12 x a x 
orange 17 22 x x r 
blueberry 14 22 x x l 

,如果你想要一些列标题和更好的输出格式:

$ cat tst.awk 
NR==FNR { names[NR]=$1; money[NR]=$2; next } 
FNR==1 { 
    out = "Fruit" OFS "Min" OFS "Max" 
    for (i=1; i in names; i++) { 
     out = out OFS names[i] 
    } 
    print out 
} 
{ 
    out = $0 
    for (i=1; i in money; i++) { 
     out = out OFS ((money[i]>=$2) && (money[i]<=$3) ? substr($1,2,1) : "x") 
    } 
    print out 
} 

$ awk -f tst.awk money.txt range.txt | column -t 
Fruit  Min Max Mary Lucy Jack 
apple  10 15 p  x  x 
banana  7 12 x  a  x 
orange  17 22 x  x  r 
blueberry 14 22 x  x  l 
+1

非常感谢你@EdMorton但是我想知道'substr($ 1,2,1)'是什么意思。这是否意味着从'range.txt'中提取'$ 1'的第二个字符?如果是这样,它不是我所期望的,我想在'range.txt'中获得'$ 1'的('max_value' - 'money')字符。 – lightsnail

+1

是的,这就是它的意思。因此,如果max_value存储在$ 3中,并且钱存储在money [i]中,那么您认为您必须对substr($ 1,2,1)'做出'max_value - money'字符而不是“2”字符?欢迎来钓鱼101 :-)。 –

+1

'substr($ 1,($ 3-money [i]),1)'^ _^ – lightsnail

0

我个人不会为这种使用awk并保持它恕我直言很简单:

#!/bin/bash 

money=$(<money.txt) 
range=$(<range.txt) 

while read -r fruit min max; do 
    echo -e "$fruit $min $max \c" 
    while read -r name cash; do 
     if (($cash > $min)) && (($cash < $max)); then 
      pos=$(($max - $cash - 1)) 
      echo -e "${fruit:pos:1} \c" 
     else 
      echo -e "x \c" 
     fi 
    done <<< "$money" 
    echo 
done <<< "$range" 

输出与给定源数据所描述的完全相同,并且该逻辑也应该对其他数据一致地工作。 :)

+0

您应该阅读[为什么要使用shell循环处理文本被认为是坏行为](http://unix.stackexchange.com/questions/169716/why -shell-loop-to-process-text-considered-bad-practice)来学习一些为什么你应该为此使用awk的原因。此外,您的方法会非常缓慢,因为它会多次读取money.txt。不要按惯例对非导出的变量名称使用全部大写,并避免与内建和导出的名称冲突,并且由于您对某些脚本使用数学运算符'((...))',只需使用那么为了清晰和一致,所有这一切都是一样的。 –

+0

点了,我已经纠正了我的一些坏习惯。 :)最初当测试时,我有变量中的数据,因为我不想费心去创建它们。最后,我只是将它改为从文件读取以匹配OP的问题,但没有意识到它会导致磁盘冗余读取。 –

相关问题