Bashスクリプトでエラーを抑制する方法

Bashスクリプトでエラーを抑制する方法

dateコマンドで生成されたエラーを抑制しようとしましたが、スクリプトを実行した後もエラーが発生します。

#!/usr/bin/bash

input="30 FEB 2022"
reg="^[0-9]{1,2}\s[a-zA-Z]{1,3}\s[0-9]{1,4}$"

if [[ $input =~ $reg ]]
then
        echo "VALID Date Format : $input"
        #output=$(`date -d "$input" +"%d-%b-%Y, %A"` 2>&1 > /dev/null)
        output=`date -d "$input" +"%d-%b-%Y, %A"` 2>&1 > /dev/null
else
        echo "INVALID Date Format : $input"
        output="-1"
fi

echo $output

実行後の出力 -

root@ip-xx-x-xx-xxx:~# ./exDate.sh 
VALID Date Format : 30 FEB 2022
date: invalid date '30 FEB 2022'

エラーを抑制する方法を教えてください。

答え1

より良い方法を提供する回答がすでにあるので、あなたが要求した質問にのみ答えます。エラーメッセージが引き続き表示されるのは、リダイレクトの順序が重要なためです。リダイレクトは左から右に読み込まれるため、2>&1 > /dev/null「最初にstderrをstdoutにリダイレクトしてから」を意味します。それからstdoutを/dev/null「にリダイレクトします。これはエラーがstdoutとして印刷され、通常のstdoutがにリダイレクトされることを意味します。stdout/dev/nullを次にパイプすることでこれを確認できますwc

## No redirection
$ date -d foo 
date: invalid date ‘foo’

## Nothing is printed to stdout, the error goes to stderr
## and wc has nothing to count
$ date -d foo | wc
date: invalid date ‘foo’
      0       0       0

## Redirect using 2>&1 > /dev/null
$ date -d foo 2>&1 > /dev/null
date: invalid date ‘foo’

## The error is now being printed to stdout, wc counts it
$ date -d foo 2>&1 > /dev/null | wc
      1       4      29

あなたが望むのは、標準出力を/dev/null最初の出力にリダイレクトし、それからstderrをstdoutにリダイレクトします> /dev/null 2>&1。期待どおりに動作します。

$ date -d foo  > /dev/null 2>&1 
$ 

答え2

正規表現やパターンを使用して日付を確認することはできません。 (まあ、おそらくそうすることができるようですが、それは不快です。)

代わりに、dateコマンド自体を使用して入力を検証します。このスクリプトをファイルに作成exDateして実行可能にします(chmod a+x exDate)。

#!/bin/bash

input=$1
if date --date "$input" >/dev/null 2>&1
then
    # Good date
    output=$(date --date "$input" +'%d-%b-%Y, %A')
else
    # Date parsing failed
    printf 'INVALID Date Format : %s\n' "$input" >&2
    output='-1'
fi

printf "%s\n" "$output"

実行例

./exDate '30 FEB 2022'
INVALID Date Format : 30 FEB 2022
-1

./exDate '24 FEB 2022'
24-Feb-2022, Thursday

./exDate '2022-04-13'
13-Apr-2022, Wednesday

最後のオプションが許可されていない場合(つまり、フォームの日付のみを許可したい場合d(d) MMM yyyy)、次のようにパターンマッチングとdate検証が必要です。

if [[ "$input" =~ ^[0-9]{1,2}\ [a-zA-Z]{3}\ [0-9]{4}$ ]] && date…
then

if date...割り当てとマージしてコードを単純化output=し、失敗したケースを処理するだけです。

if ! output=$(date --date "$input" +'%d-%b-%Y, %A' 2>/dev/null)
then
    # Date parsing failed
    printf 'INVALID Date Format : %s\n' "$input" >&2
    output='-1'
fi

答え3

デフォルトの入力日付形式は米国です。月は日付の前になければなりません。

$ date -d '02/02/2022'
Wed 02 Feb 2022 12:00:00 AM UTC

$ date -d '02/22/2022'
Wed 22 Feb 2022 12:00:00 AM UTC

はい、月は文字で表示できます(ロケールが他の国にある場合でもFEBまたは2月)。

$ date -d 'FEB 22 2022'
Tue 22 feb 2022 00:00:00 UTC

$ ( LC_ALL=es_ES.utf8 date -d 'FEB 22 2022')
mar 22 feb 2022 00:00:00 UTC

$ ( LC_ALL=ja_JP.utf8 date -d 'FEB 22 2022')
2022年  2月 22日 火曜日 00:00:00 UTC

ただし、どんな日付でも可能ではありません。いいえ日付が与えられたら、エラーを報告してみてください。存在しない。 2月30日は存在しません。この場合、日付は出力されません。そして終了状態を1に設定します。実際には、正規表現がなくても入力日を検証できます。

#!/bin/bash

input="${1:-"30 FEB 2022"}"

if     output=`date -d "$input" +"%d-%b-%Y, %A" 2>&1`
then   echo "VALID   Date : $input"        
else   echo "INVALID Date : $input"
       output="-1"
fi

printf '%s\n' "$output"

もちろん、リダイレクトは次の場所になければなりません。`...`彼らが働くようにしてください。

$ ./exDate.sh
INVALID Date : 30 FEB 2022
-1

$ ./exDate.sh "22 FEB 2022"
INVALID Date : 22 FEB 2022
-1

$ ./exDate.sh "FEB 22 2022"
VALID   Date : FEB 22 2022
22-Feb-2022, Tuesday

$ ./exDate.sh "FEB 30 2022"
INVALID Date : FEB 30 2022

関連情報