プログラムが複数行を返す場合、パイプラインの終了

プログラムが複数行を返す場合、パイプラインの終了

私はデータベース名を取得するためにスキーマでmysqlデータベースを照会しています。現在の実装は次のとおりです。

include_databases=$(mysql --batch --skip-column-names --execute "SHOW DATABASES LIKE 'foo%'" \
    | paste -sd ",")

これにより、パターンと一致するデータベース名のカンマ区切りリストが返されます。

しかし、実際にはデータベース名だけが返されると予想しており、mysqlが2行の結果を返すときにエラーを発生させる方が良いと思います。

次のようなものがありますか?

include_databases=$(mysql --batch --skip-column-names --execute "SHOW DATABASES LIKE 'foo%'" \
    | __error_if_two_lines__ )

答え1

head以下を使用して最初の行を抽出できます。

include_databases=$(… | head -n 1)

ただし、これは追加の行を自動的に無視します。より多くの行がある場合は、awkを使用して別の終了コードを返すことができます。

include_databases=$(… | awk 'NR>1 {exit(2)} 1')
if [ $? -ne 0 ]; then
  echo >&2 'mysql returned multiple lines! Aborting.'; exit 2;;
fi

またはset -e:

include_databases=$(… | awk 'NR>1 {print "mysql returned multiple lines! Aborting." >"/dev/stderr"; exit(2)} 1')

または、出力を変数に保存し、改行文字が含まれているかどうかをテストすることもできます。 (コマンドの最後の改行文字はコマンド置換には含まれません.)

include_databases=$(…)
nl='
'
case $include_databases in
  *"$nl"*) echo >&2 'mysql returned multiple lines! Aborting.'; exit 2;;
esac

ksh/bash/zshでは、通常のshではなく、このコードをより簡潔な方法で記述できます。

include_databases=$(…)
if [[ "$include_databases" = *$'\n'* ]]; then
  echo >&2 'mysql returned multiple lines! Aborting.'; exit 2;;
esac

答え2

私は彼をあなたの友人だと思いますwc。オプションを使用して行数-lと単語数を計算します-w。 (マンページ参照)

mysql --batch --skip-column-names --execute "SHOW DATABASES" | wc -w

データベースの数を表示します。

たとえば、

include_databases=$(mysql --batch --skip-column-names --execute "SHOW DATABASES")
numDB=$(echo $include_databases | wc -w)
[ $numDB -gt 1 ] && echo -n "$numDB dbs is more than "
echo "one db"

ヒント:このスクリプトは多くのサブシェルを使用しているため、改善する必要があります。

関連情報