プログラムが1行以上を返す場合はパイプを終了します

プログラムが1行以上を返す場合はパイプを終了します

パターン別にデータベース名を MySQL データベースにクエリしています。現在、私の実装は次のようになります。

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

パターンに一致するデータベース名のコンマ区切りリストを返します。

ただし、実際には 1 つのデータベース名のみが返されることが想定されており、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単語数を数えます。(man ページを参照)

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"

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

関連情報