我试图同时读入两个文件(名称,编号),并获取每个可能对的值。 这两个文件是这样的:
*name1
John
*name2
Paul
*number1
25
*number2
45
我要获取的是标签和结果,如:
*name1 *number1 John 25
*name2 *number2 John 45
*name2 *number1 Paul 25
*name2 *number2 Paul 45
自从我来自python以来,我就尝试通过两个循环来做到这一点:
name=/home/davide/name.txt
number=/home/davide/number.txt
while read name; do
if [[ ${name:0:1} == "*" ]]; then
n=$(echo $name)
else
while read number; do
if [[ ${number:0:1} == "*" ]]; then
echo $number $n
else
echo $name $number
fi
done < $number
fi
done < $name
我有前两对,所以我猜这是我需要一个从数字开头重新开始的命令(例如python上的seek(0)),但我没有找到类似的bash命令。 我还收到“歧义重定向”错误,我不明白为什么。
答案 0 :(得分:1)
设置输入文件后:
printf >name.txt '%s\n' '*name1' John '*name2' Paul
printf >number.txt '%s\n' '*number1' 25 '*number2' 45
...以下代码:
#!/usr/bin/env bash
name_file=name.txt
number_file=number.txt
while IFS= read -r name1 && IFS= read -r value1; do
while IFS= read -r name2 && IFS= read -r value2; do
printf '%s\n' "$name1 $name2 $value1 $value2"
done <"$number_file"
done <"$name_file"
...正确输出:
*name1 *number1 John 25
*name1 *number2 John 45
*name2 *number1 Paul 25
*name2 *number2 Paul 45
发生了什么变化?
name
和number
用于文件名和从它们读取的值。因此,当您运行<$number
时,它在第一次迭代后就不再具有文件名number.txt
了; $name
也是如此。"$foo"
,而不是$foo
)。请参见http://shellcheck.net/警告SC2086和BashPitfalls #14,解释为什么甚至echo $foo
都是越野车。read
参数和-r
设置为空值的情况下运行IFS
可以防止它消耗文字反斜杠或修剪开头和结尾的换行符。read
循环的条件下使用两个while
可以让我们一次从每个文件中读取两行(适当的话,要成对地处理内容)。答案 1 :(得分:0)
Bash在“流”上更轻松地操作,而不是在数据本身上。
*name1 John *number1 25
到*name1 *number1 John 25
的列
cat >name.txt <<EOF
*name1
John
*name2
Paul
EOF
cat <<EOF >number.txt
*number1
25
*number2
45
EOF
paste <(<name.txt sed 'N;s/\n/\t/') <(<number.txt sed 'N;s/\n/\t/') |
awk '{print $1,$3,$2,$4}'
将输出:
*name1 *number1 John 25
*name2 *number2 Paul 45
答案 2 :(得分:0)
首先,在您的示例中,您覆盖了变量$number
。因此,从第二次循环运行开始,您在读取文件$number
时遇到问题。
粘贴解决方案
命令paste
可以合并多个文件,并可以逐行选择选项-d
。
#!/usr/bin/env bash
name=/home/davide/name.txt
number=/home/davide/number.txt
# combine both files linb-by-line
paste $'-d\n' "$name" "$number" |
while read nam
do
#after reading name to var 'nam', read number to var 'num':
read num
# print both
echo "$nam $num"
done
如果您需要TABS或任何其他分隔符,而无需其他处理,则不需要while循环。例子
paste "$name" "$number"
paste -d: "$name" "$number"
paste -d\| "$name" "$number"
答案 3 :(得分:0)
$ cat tst.awk
NR==FNR {
if ( NR%2 ) {
tags[++numPairs] = $0
}
else {
vals[numPairs] = $0
}
next
}
!(NR%2) {
for (pairNr=1; pairNr<=numPairs; pairNr++) {
print prev, tags[pairNr], $0, vals[pairNr]
}
}
{ prev = $0 }
$ awk -f tst.awk number.txt name.txt
*name1 *number1 John 25
*name1 *number2 John 45
*name2 *number1 Paul 25
*name2 *number2 Paul 45