将读取的光标返回到文件的开头

时间:2019-05-08 14:35:31

标签: bash

我试图同时读入两个文件(名称,编号),并获取每个可能对的值。 这两个文件是这样的:

*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命令。 我还收到“歧义重定向”错误,我不明白为什么。

4 个答案:

答案 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

发生了什么变化?

  • 我们不再将namenumber用于文件名和从它们读取的值。因此,当您运行<$number时,它在第一次迭代后就不再具有文件名number.txt了; $name也是如此。
  • 我们开始引用所有扩展名("$foo",而不是$foo)。请参见http://shellcheck.net/警告SC2086BashPitfalls #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