用于循环调用功能的shell转储负数

时间:2019-02-15 08:16:20

标签: bash shell

我编写了一个shell脚本来自动生成内核代码:

#!/bin/bash
# -----------------------------------------------------------
# Description: Register Blocking CSR kernel auto generation.
# -----------------------------------------------------------

#set -x

KERNEL_SRC=kernel.cpp

file_gen() {
    if [ -f ${KERNEL_SRC} ]
    then
        rm -f ${KERNEL_SRC}
        touch ${KERNEL_SRC}
    fi
    echo "/*">>${KERNEL_SRC}
    echo " *   Register Blocking CSR implement.">>${KERNEL_SRC}
    echo " *">>${KERNEL_SRC}
    echo " */">>${KERNEL_SRC}
    echo >>${KERNEL_SRC}
    echo >>${KERNEL_SRC}
}

emit_func_header() {
    R=$1
    C=$2
    echo "void bcsr_${R}x${C}(const int &bm, const int *b_row_start, const int *b_col_idx," >> ${KERNEL_SRC}
    echo "const double *b_values, const double *x, double *y) {" >> ${KERNEL_SRC}
}

emit_func_body() {
    local R=${1}
    local C=${2}
    #echo ${R} ${C}
    echo "int i, j;" >>${KERNEL_SRC}
    echo "double" >>${KERNEL_SRC}

    local m=$(( ${R} - 1 ))
    # emit d0, d1, ..., d(r-1), x0, x1, ..., x(c-1)
    for i in `seq 0 $m`
    do
        echo "d${i}, ">>${KERNEL_SRC}
    done
    local t=$(( ${C} - 1 ))
    for i in `seq 0 $t`
    do
        if [ ${i} -eq ${t} ]
        then
            echo "x${i};">>${KERNEL_SRC}
        else
            echo "x${i}, ">>${KERNEL_SRC}
        fi
    done
    # emit outer loop
    echo "for (i = 0; i < bm; ++i) {">>${KERNEL_SRC}
    # init d0, d1, ..., d(r-1)
    for i in `seq 0 $m`
    do
        echo "d${i} = y[${R} * i + ${i}];">>${KERNEL_SRC}
    done
    # emit inner loop
    echo "for (j = b_row_start[i]; j < b_row_start[i + 1]; ++j, b_values += ${R} * ${C}) {">>${KERNEL_SRC}
    # init x0, x1, ..., x(c-1)
    for i in `seq 0 $t`
    do
        echo "x${i} = x[${C} * b_col_idx[j] + ${i}];">>${KERNEL_SRC}
    done
    # reduce d0, d1, ..., d(r-1)
    for i in `seq 0 $t`
    do
        for j in `seq 0 $m`
        do
            index=$(( $(( ${j} * ${C} )) + ${i} ))
            echo "d${j} += b_values[${index}] * x${i};">>${KERNEL_SRC}
        done
    done
    # write back d0, d1, ..., d(r-1)
    for i in `seq 0 $m`
    do
        echo "y[${R} * i + ${i}] = d${i};">>${KERNEL_SRC}
    done
    # end inner loop
    echo "}">>${KERNEL_SRC}
    # end outer loop
    echo "}">>${KERNEL_SRC}
}

emit_func_tail() {
    echo "}" >> ${KERNEL_SRC}
}

echo "Begin to generate kernel..."
file_gen
for i in `seq 1 12`
do
    for j in `seq 1 12`
    do
        echo ${i} ${j}
        emit_func_header ${i} ${j}
        emit_func_body ${i} ${j}
        emit_func_tail
        echo >>${KERNEL_SRC}
    done
done
#clang-format -i $KERNEL_SRC
echo "End kernel generating..."

期望: 带有代码的kernel.cpp:

void bcsr_1x1(...) {...}
void bcsr_1x2(...) {...}
...
void bcsr_1x12(...) {...}
void bcsr_2x1(...) {...}
...
void bcsr_2x12(...) {...}
...
void bcsr_12x12(...) {...}

总共144个bcsr子例程,但实际输出包含负数,例如:

bcsr_ - 1x3(...)

由于核心代码是:

for i in `seq 1 12`
do
    for j in `seq 1 12`
    do
        echo ${i} ${j}
        emit_func_header ${i} ${j}
        emit_func_body ${i} ${j}
        emit_func_tail
        echo >>${KERNEL_SRC}
    done
done

外循环的范围是1到12,内循环的范围是1到12,其预期输出不应包含任何负数。

bash版本: GNU bash版本3.2.57(1)-发行版(x86_64-apple-darwin17) 版权所有(C)2007自由软件基金会,公司。

2 个答案:

答案 0 :(得分:0)

这可能是一个范围问题,当我使用其他名称更改循环索引时,称为函数emit_func_body的内部循环包含局部变量i, 一切正常:

for _i in `seq 1 12`
do
    for _j in `seq 1 12`
    do
        echo ${_i} ${_j}
        emit_func_header ${_i} ${_j}
        emit_func_body ${_i} ${_j}
        emit_func_tail
        echo >>${KERNEL_SRC}
    done
done

答案 1 :(得分:0)

其中一个函数使用全局变量i并覆盖主循环中的值。

快速解决方案是将local i添加到要使用此变量作为局部变量的任何函数,并通常检查所有函数以确保将其使用的所有变量都声明为local

如果您不打算将其全部重写为具有更好的范围规则的语言,我还建议您为所有变量添加适当的引号,并检查Shell脚本的重定向规则。特别是,将所有诊断消息打印为标准错误,并在主循环中使用单个重定向。

# Correspondingly refactor file_gen; no need to rm or touch
file_gen >"$KERNEL_SRC"
for i in `seq 1 12`
do
    for j in `seq 1 12`
    do
        echo "$i $j" >&2
        emit_func_header "$i" "$j"
        emit_func_body "$i" "$j"
        emit_func_tail
        echo
    done
done  >>"$KERNEL_SRC"

只要您仍在使用Bash,您可能还想用传统的三参数seq循环替换for