年月を別の形式に変換する

年月を別の形式に変換する

形式に年と月がありYYMM、それを形式に変換したいと考えていますYYYY Month。年は常に 2000 以降です。たとえば、

  • 1908なる2019 Aug
  • 1904なる2019 Apr
  • 2012なる2020 Dec
  • 2111なる2021 Nov

以下に示すスクリプトを作成しました。

rand=(1908 1904 2012 2001 2111)
months=(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
for i in $rand
do
    echo ${i:2:2}
    if [ ${i:2:2} -lt 1 ] || [ ${i:2:2} -gt 12 ]
        then echo "Month: ${i:2:2}. Last 2 values must be a month between 01 and 12."
    fi

    printf "20${i:0:2} ${months[${i:2:2}]}"
done

しかし、いくつかエラーが発生します。

line 13: 08: value too great for base (error token is "08")

ゼロを埋め込んだ 1 桁の月は、場所によっては問題になるものの、他の場所では機能すると思います。

08が であることを Bash に理解させる方法がわかりません。に8変更しようとしました。 しかし、うまくいきません。${i:2:2}$((i:2:2))

line 7: i:2:2: syntax error in expression (error token is ":2:2")

答え1

08は無効な 8 進数として解釈されます。 0 で始まるので 8 進数ですが、 が含まれているので無効です8。これは、この部分文字列を算術コンテキスト (整数比較) で数値として使用しているために発生します。 でも同じ問題が発生しますが、またはそれ以下の数値09では発生しません07

次のスクリプトは、日付 2000-01-01 にYY数字のビットを足して年として計算を行います。次に、文字列の残りを月数として加算し、1 日を減算します。この計算により、コードがYYMM参照する月の最終日が算出されます。 を使用すると%Y %b、年と月がYYYY Mon形式で出力されます。

#!/bin/bash

datecodes=(1908 1904 2012 2001 2111)

for datecode in "${datecodes[@]}"; do
        printf -v thedate '2000-01-01 +%s years +%s months -1 day' "${datecode:0:2}" "${datecode:2}"
        LC_ALL=C date -d "$thedate" +'%Y %b'
done

出力:

2019 Aug
2019 Apr
2020 Dec
2020 Jan
2021 Nov

GNU を一度だけ呼び出す、少しだけ効率的なコードdate:

#!/bin/bash

datecodes=(1908 1904 2012 2001 2111)

for datecode in "${datecodes[@]}"; do
        printf '2000-01-01 +%s years +%s months -1 day\n' "${datecode:0:2}" "${datecode:2}"
done | LC_ALL=C date -f - +'%Y %b'

2013 Aprこのコードでは、例えばというコードを書くことができることに注意してください1040

POSIX ロケールではなく現在のロケールに従ってフォーマットされた短縮月の名称を取得するには、LC_ALL=Cの呼び出しの前の を削除しますdate


GNU を使わずにdate、あなたと同じアプローチを使用して、日付コードの月部分の検証を行います。

#!/bin/bash

datecodes=(1908 1904 2012 2001 2111 1040)

declare -A months
months=(
        [01]=Jan [02]=Feb [03]=Mar
        [04]=Apr [05]=May [06]=Jun
        [07]=Jul [08]=Aug [09]=Sep
        [10]=Oct [11]=Nov [12]=Dec
)

for datecode in "${datecodes[@]}"; do
        YY=${datecode:0:2}
        MM=${datecode:2}

        if [ -z "${months[$MM:-empty]}" ]; then
                printf '"%s" is an invalid month\n' "$MM" >&2
                continue
        fi

        printf '20%s %s\n' "$YY" "${months[$MM]}"
done

これは をmonths連想配列として使用します。

答え2

以下の方法で実行します。上記の入力に日付を追加して、目的の出力を取得します。

ここで、構造化するために言及された入力に日付「01」を追加しました。有効な入力になります。

for i in 1908 1904 2012 2111; do date +%Y" "%b -d $i"01"; done

出力

2019 Aug
2019 Apr
2020 Dec
2021 Nov

関連情報