Bash 如何在几秒钟内创建大型CSV?

Bash 如何在几秒钟内创建大型CSV?,bash,csv,Bash,Csv,我正在尝试快速创建1000个大型CSV。此函数生成CSV: function csvGenerator () { for ((i=1; i<=$NUMCSVS; i++)); do CSVNAME=$DIRNAME"-"$CSVPREFIX$i$CSVEXT HEADERARRAY=() if [[ ! -e $CSVNAME ]]; then #Only create csv file if it not exist touch $CSVNAM

我正在尝试快速创建1000个大型CSV。此函数生成CSV:

function csvGenerator () {

  for ((i=1; i<=$NUMCSVS; i++)); do
    CSVNAME=$DIRNAME"-"$CSVPREFIX$i$CSVEXT
    HEADERARRAY=()

    if [[ ! -e $CSVNAME ]]; then #Only create csv file if it not exist
      touch $CSVNAME
      echo "file: "$CSVNAME "created at $(date)" >> ../status.txt
    fi

    for ((j=1; j<=$NUMCOLS; j++)); do

      if  (( j < $NUMCOLS )) ; then
        HEADERNAME=$DIRNAME"-csv-"$i"-header-"$j", "
      elif (( j == $NUMCOLS )) ; then
        HEADERNAME=$DIRNAME"-csv-"$i"-header-"$j
      fi
      HEADERARRAY+=$HEADERNAME

    done

    echo $HEADERARRAY > $CSVNAME

    for ((k=1; k<=$NUMROWS; k++)); do
      ROWARRAY=()

      for ((l=1; l<=$NUMCOLS; l++)); do

        if (( l < $NUMCOLS )) ; then
          ROWVALUE=$DIRNAME"-csv-"$i"-r"$k"c"$l", "
        elif (( l == $NUMCOLS )) ; then
          ROWVALUE=$DIRNAME"-csv-"$i"-r"$k"c"$l
        fi
        ROWARRAY+=$ROWVALUE

      done

      echo $ROWARRAY >> $CSVNAME

    done

  done

}

该脚本需要约3分钟才能生成一个包含100k行和70列的CSV。我需要做什么才能以1csv/~10秒的速度生成这些CSV?

将两个内部for循环重构为这样的循环将节省时间:

for ((j=1; j<$NUMCOLS; ++j)); do
  HEADERARRAY+=$DIRNAME"-csv-"$i"-header-"$j", "
done
HEADERARRAY+=$DIRNAME"-csv-"$i"-header-"$NUMCOLS

将两个内部for循环重构为这样的循环将节省时间:

for ((j=1; j<$NUMCOLS; ++j)); do
  HEADERARRAY+=$DIRNAME"-csv-"$i"-header-"$j", "
done
HEADERARRAY+=$DIRNAME"-csv-"$i"-header-"$NUMCOLS

让我首先说,bash和performant通常不会在同一句话中同时出现。正如其他评论员所建议的,awk可能是一个很好的选择,在某些意义上是相邻的

我还没有机会运行您的代码,但它每行打开和关闭输出文件一次——在本例中,是100000次。每次它都必须搜索到文件的末尾,以便可以追加最新的行


尝试在j=1的情况下拉取实际的生成;首先,让我说bash和performant通常不会在同一句话中同时出现。正如其他评论员所建议的,awk可能是一个很好的选择,在某些意义上是相邻的

我还没有机会运行您的代码,但它每行打开和关闭输出文件一次——在本例中,是100000次。每次它都必须搜索到文件的末尾,以便可以追加最新的行


尝试在j=1的情况下拉取实际的生成;我想答案不是这样的

这里有一些问题

您没有将数组用作数组。如果将它们视为字符串,则只会影响数组中的第一个元素,这会产生误导。 您使用>>的方式会导致每行打开和关闭一次输出文件。这可能是浪费。 你没有引用你的变量。事实上,你引用的是那些不需要引用的东西,而不是引用那些需要引用的东西。 由于存在与系统变量冲突的风险,不建议使用大写变量名。 Bash不擅长这个。真正地 清理后的函数版本可能如下所示:

csvGenerator2() {

  for (( i=1; i<=NUMCSVS; i++ )); do
    CSVNAME="$DIRNAME-$CSVPREFIX$i$CSVEXT"

    # Only create csv file if it not exist
    [[ -e "$CSVNAME" ]] && continue

    touch "$CSVNAME"
    date "+[%F %T] created: $CSVNAME" | tee -a status.txt >&2

    HEADER=""
    for (( j=1; j<=NUMCOLS; j++ )); do
      printf -v HEADER '%s, %s-csv-%s-header-%s' "$HEADER" "$DIRNAME" "$i" "$j"
    done

    echo "${HEADER#, }" > "$CSVNAME"

    for (( k=1; k<=NUMROWS; k++ )); do

      ROW=""
      for (( l=1; l<=NUMCOLS; l++ )); do
        printf -v ROW '%s, %s-csv-%s-r%sc%s' "$ROW" "$DIRNAME" "$i" "$k" "$l"
      done

      echo "${ROW#, }"

    done >> "$CSVNAME"

  done

}

请注意,即使是我的优化bash版本也只比您的原始代码快一点。

我认为答案不是这样

这里有一些问题

您没有将数组用作数组。如果将它们视为字符串,则只会影响数组中的第一个元素,这会产生误导。 您使用>>的方式会导致每行打开和关闭一次输出文件。这可能是浪费。 你没有引用你的变量。事实上,你引用的是那些不需要引用的东西,而不是引用那些需要引用的东西。 由于存在与系统变量冲突的风险,不建议使用大写变量名。 Bash不擅长这个。真正地 清理后的函数版本可能如下所示:

csvGenerator2() {

  for (( i=1; i<=NUMCSVS; i++ )); do
    CSVNAME="$DIRNAME-$CSVPREFIX$i$CSVEXT"

    # Only create csv file if it not exist
    [[ -e "$CSVNAME" ]] && continue

    touch "$CSVNAME"
    date "+[%F %T] created: $CSVNAME" | tee -a status.txt >&2

    HEADER=""
    for (( j=1; j<=NUMCOLS; j++ )); do
      printf -v HEADER '%s, %s-csv-%s-header-%s' "$HEADER" "$DIRNAME" "$i" "$j"
    done

    echo "${HEADER#, }" > "$CSVNAME"

    for (( k=1; k<=NUMROWS; k++ )); do

      ROW=""
      for (( l=1; l<=NUMCOLS; l++ )); do
        printf -v ROW '%s, %s-csv-%s-r%sc%s' "$ROW" "$DIRNAME" "$i" "$k" "$l"
      done

      echo "${ROW#, }"

    done >> "$CSVNAME"

  done

}

请注意,即使是我优化的bash版本也只比您的原始代码快一点。

使用多线程来加速您的任务。您能给我一些关于如何进行的指导吗?所有代码都在一个文件中。我查看了一些示例,但不确定它们是否适用于我的情况。如果您想要速度,请不要使用bash。这就是真正的编程语言的用途。C,C++,java,python,Ruby,JavaScript…选择你的毒药:-正是斯蒂芬C说的。这是做这项工作的错误工具。即使是awk也是一个更好的选择。Awk实际上可能是一个很好的选择。使用多线程加速你的任务你能给我一些关于如何进行的指导吗?所有代码都在一个文件中。我查看了一些示例,但不确定它们是否适用于我的情况。如果您想要速度,请不要使用bash。这就是真正的编程语言的用途。C,C++,java,python,Ruby,JavaScript…选择你的毒药:-正是斯蒂芬C说的。这是做这项工作的错误工具。即使是awk也是一个更好的选择。Awk实际上可能是一个很好的选择。
$ time bash -c '. file; NUMCSVS=1 NUMCOLS=10 NUMROWS=100000 DIRNAME=2 CSVPREFIX=x CSVEXT=.csv csvGenerator2'
[2019-03-29 23:57:26] created: 2-x1.csv

real    0m30.260s
user    0m28.012s
sys     0m1.395s
$ time bash -c '. file; NUMCSVS=1 NUMCOLS=10 NUMROWS=100000 DIRNAME=3 CSVPREFIX=x CSVEXT=.csv csvGenerator3'
[2019-03-29 23:58:23] created: 3-x1.csv

real    0m4.994s
user    0m3.297s
sys     0m1.639s