形式に年と月があり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