我正在编写 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
实际上不需要for
or循环。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; done
,zsh
尚不支持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
,默认包含空格、制表符和换行符)。