FOR 循环:同时从文件传递 2 个变量

FOR 循环:同时从文件传递 2 个变量

我正在编写 shell 脚本,从文件中提取 2 个变量,并使用了下面的 FOR 循环。

for i j in `cat list`
                do
                echo title
                echo total "$i" "," "$j"
                echo end
done

猫列表在哪里

AAA 111
BBB 222
CCC 333

意外出现“j”错误,我使用了“while 循环”,但没有运气。

期望输出是

title
total AAA,111
total BBB,222
total CCC,333
end

答案1

实际上不需要foror循环。while这些命令中的任何一个awk都可以工作:

awk 'BEGIN {print "title"}
           {print "total",$1","$2}
       END {print "end"}' list

或者:

awk 'BEGIN {print "title"}
           {printf "total %s,%s\n", $1, $2}
       END {print "end"}' list

在读取文件中的数据之前,打印BEGIN{print "title"}该单词一次。title

{print "total",$1","$2}打印单词total,后跟一个不带引号的逗号,表示列 columns 中的值之间的空格,然后打印列本身。该块针对每个输入行执行。

END{print "end"}打印文件的单词end和结尾。 END 告诉它在读取文件的最终输入后​​执行该块。

对于第二个命令:

唯一的区别是:

{printf "total %s,%s\n", $1, $2}

这使用printf而不是print第一个参数定义格式的位置。

%s,%s告诉它打印 和 的值$1$2以逗号分隔,并且\n代表一个新行,以便移动到下一行并打印$1和的值,$2直到文件末尾。

就我个人而言,我会使用第二个命令,printf因为您可以只使用一组引号,而不是同时引用total和逗号。正如您在阅读其手册页中会发现的那样,它也更加模块化。我仅包含两个命令来显示两种不同的方式。

输出

title
total AAA,111
total BBB,222
total CCC,333
end

答案2

您可以使用,while read

echo "title"
while read -r i j
do
    echo total "$i,$j"
done < list
echo "end"

它将给出输出:

title
total AAA,111
total BBB,222
total CCC,333
end

答案3

虽然使用文本处理实用程序可以更好地解决您的具体问题就像awk@Nasir 所示(也可以看看为什么使用 shell 循环处理文本被认为是不好的做法?),我来回答标题中的问题。

is语法for i j in words...; do something with $i and $j; donezsh尚不支持bash

bash执行分割(您想要的)和通配符(您不想要的)`cmd`(命令替换的过时形式,您可能想要切换到$(cmd)),而zsh只按照您的预期进行分割。

bash要使用或其他类似 POSIX 的 shell一次处理两个单词,for i j in words...您可以执行以下操作:

set -- words...
while [ "$#" -gt 0 ]; do
  i=$1 j=$2 # or j=${2-missing}
  something with "$i" and "$j"
  shift "$(( 2 - ($# == 1) ))"
done

在你的情况下,set看起来像:

set -o noglob # disable globbing
set -- $(cat list)

(假设未修改$IFS,默认包含空格、制表符和换行符)。

相关内容