【问题标题】:Why does unsetting first element of an array in bash wipe the whole thing?为什么在 bash 中取消设置数组的第一个元素会擦除整个内容?
【发布时间】:2019-05-18 01:22:58
【问题描述】:

我前段时间编写了一个脚本来处理一些以几周、几个月甚至几年为单位的日常数据。我需要做的一件事是删除第一个元素,否则我最终会在结果中出现重复的条目。该脚本可以创造奇迹。快进几个月,我需要制作一个相同的脚本,该脚本在调用某些二进制文件和脚本来处理数据方面有所不同。我复制了脚本并进行了相关更改,保留了日期序列的生成和第一个元素的删除。当我运行这个新脚本时,当为第一个元素调用 unset 时,整个日期数组都会被取消设置。

这是脚本:

#!/bin/sh

if [ "$1" = '' ] || [ "$3" = '' ]; then
    echo -e "Uso:\t$0 <estacion> <inicio> <fin>"
    echo
    echo -e "\tEl argumento 'estacion' es el identificador de una de las estaciones en"
    echo    "maysculas (e.g. RMA1_FDC). Los otros dos--'inicio' y 'fin'--son fechas de la"
    echo    "forma AAAA-[M]M-[D]D, dondeA corresponde a un digito del año, M para el mes, y D"
    echo    "para el dia. Notese que el mes y el dia solo requieren un digito si el valor"
    echo    "para este campo es menor a diez. No es necesario poner '0' adelante del numero"
    echo    "en este caso."
    echo
    echo    "Este programa genera datos en formato CSV (coma separated values) en la salida"
    echo    "estandar. Si desea guardarlos a un archivo, redirija la salida al mismo. Ej."
    echo
    echo    "$0 RMA1_FDC 2018-7-1 2018-12-10 > registro.csv"
    echo

    exit -1
fi

PRECIPITACION_MODELO=2
PRECIPITACION_ESTACION=5
DIA_A=$2
FECHAS=$(seq $(date +%s -d $2) 86400 $(date +%s -d $3))
>&2 echo "Fechas = "${FECHAS[*]}
unset -v FECHAS[0]
>&2 echo "Fechas = "${FECHAS[*]}

echo "fecha,'delta precipitacion',corrida"

for d in ${FECHAS[@]}; do
    DIA_B=$(date +%Y-%-m-%-d -d @$d)
    >&2 echo "$DIA_A -- $DIA_B"
    ./getstationdata  $1 $DIA_A $DIA_B $PRECIPITACION_ESTACION > estacion 2> /dev/null

    ./getwrfdata  $1 $DIA_A $DIA_B $PRECIPITACION_MODELO A > pronostico 2> /dev/null
    echo -n "$DIA_A,"
    ./delta-precipitacion 2> /dev/null | awk 'ORS=NR%3?" ":"\n"' | awk '{print $2 ",A"}'

    ./getwrfdata  $1 $DIA_A $DIA_B $PRECIPITACION_MODELO B > pronostico 2> /dev/null
    echo -n "$DIA_A,"
    ./delta-precipitacion 2> /dev/null | awk 'ORS=NR%3?" ":"\n"' | awk '{print $2 ",B"}'

    ./getwrfdata  $1 $DIA_A $DIA_B $PRECIPITACION_MODELO C > pronostico 2> /dev/null
    echo -n "$DIA_A,"
    ./delta-precipitacion 2> /dev/null | awk 'ORS=NR%3?" ":"\n"' | awk '{print $2 ",C"}'

    ./getwrfdata  $1 $DIA_A $DIA_B $PRECIPITACION_MODELO D > pronostico 2> /dev/null
    echo -n "$DIA_A,"
    ./delta-precipitacion 2> /dev/null | awk 'ORS=NR%3?" ":"\n"' | awk '{print $2 ",D"}'

    DIA_A=$DIA_B;
    DIA_B=$(date +%Y-%-m-%-d -d @$d)
done

rm -f estacion pronostico

注意它说的部分

>&2 echo "Fechas = "${FECHAS[*]}
unset -v FECHAS[0]
>&2 echo "Fechas = "${FECHAS[*]}

我得到一系列数字,代表第一个“回声”的日期,但是一个简单的“FECHAS =”,第二个则没有。我已经为此困扰了一个星期。有谁知道它有什么问题吗?

【问题讨论】:

  • FECHAS 不是一个数组,您可以使用FECHAS=$(cmd) 创建它,但是要获得一个数组,您需要FECHAS=($(cmd))。话虽这么说,您的 shebang 行应该包含/bin/sh,因为这首先不支持数组 - 请改用/bin/bash/usr/bin/env bash
  • 什么是FECHAS,本来应该是一个数组,但看起来是用作变量
  • Benjamin W,D'OH! 谢谢。刚查了原版,果然不一样。您能否将其作为答案而不是评论,以便我可以将其标记为解决方案?谢谢!
  • 其他人的回答已经完美涵盖了。旁注:shellcheck.net 不会告诉你确切的问题,但其他人(例如-1 不是有效的退出状态)。
  • 是的,但是指出 FECHAS 的初始化错误是我的问题的解决方案,并且作为第一个有用的答案就是全部(当我得到通知您的回复)。初始化它们的正确方法被埋在那里,如果不看那篇文章和我的代码一百次就很难推断出我错了:)

标签: arrays bash unset


【解决方案1】:

这是重现问题的更简单方法:

var="foo bar"
echo "The value is: ${var[*]}"
unset -v 'var[0]'
echo "The value is now: ${var[*]}"

这个输出:

The value is: foo bar
The value is now:

发生这种情况是因为变量不是数组,只是 bash 允许您将常规变量视为具有单个值的数组,索引为 0:

var="foo bar"
echo "No index = $var"
echo "[0] = ${var[0]}"
echo "[1] = ${var[1]}"

输出:

No index = foo bar
[0] = foo bar
[1] =

如果您在上面的示例中使用var=("foo" "bar") 创建一个实际数组,您会得到预期的结果:

No index = foo
[0] = foo
[1] = bar
The value is: foo bar
The value is now: bar

【讨论】:

  • 在 GNU bash 版本 4.3.46 上,变量上的unset 会按预期抛出正确的错误 - bash: unset: var: not an array variable
  • 嗯。 4.4.19 不在我的系统上
  • 我要说的是:“哦 GNU!”。
  • 为什么 BASH 仍然这样做,将标量视为单元素矩阵?
  • @JamieRamone 您在标量中访问各种索引,因此 将标量视为数组。 Bash 会尽力解释您的意思。
猜你喜欢
  • 2020-02-16
  • 1970-01-01
  • 2011-09-07
  • 2022-01-18
  • 2018-11-09
  • 1970-01-01
  • 2017-09-15
相关资源
最近更新 更多