質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Ubuntu

Ubuntuは、Debian GNU/Linuxを基盤としたフリーのオペレーティングシステムです。

Azure

Azureは、マイクロソフトのクラウド プラットフォームで、旧称は Windows Azureです。PaaSとIaaSを組み合わせることで、 コンピューティング・ストレージ・データ・ネットワーキング・アプリケーションなど多くの機能を持ちます。

Q&A

解決済

3回答

1333閲覧

Bashでのコマンド失敗時、パイプで繋がれた後続コマンドを中断する方法

hkcomori

総合スコア30

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Ubuntu

Ubuntuは、Debian GNU/Linuxを基盤としたフリーのオペレーティングシステムです。

Azure

Azureは、マイクロソフトのクラウド プラットフォームで、旧称は Windows Azureです。PaaSとIaaSを組み合わせることで、 コンピューティング・ストレージ・データ・ネットワーキング・アプリケーションなど多くの機能を持ちます。

0グッド

1クリップ

投稿2020/02/27 08:35

ご質問

パイプの途中でエラーが発生したときに、パイプで繋がれた後続の処理を実行しない方法はありますか?
または、別のアプローチで同様のことが実現できる方法は無いですか?

やりたいこと

  • MySQLのバックアップ(mysqldumpをリモートのストレージに書き込みたい
  • ローカルには中間ファイルを作成する空き容量が無い
  • リモートにも、以下の理由から中間ファイルを作りたくない
    • 従量課金である (Azure Blob Storage)
    • インターネット越しであり、何度も送信して無駄に帯域を使いたくない
  • mysqldumpに失敗した場合、リモートのファイルが空ファイルまたは中途半端なファイルで上書きされることを防止したい
  • mysqldumpの失敗とは、例えば以下の状況を想定しています
    • MySQLの接続数が上限に達しており接続できない
    • MySQLサーバーが停止している等で接続できない

今検討中のコマンド

sh

1set -o pipefail 2mysqldump --defaults-file=~/my.conf \ 3 --single-transaction \ 4 --routines \ 5 --triggers \ 6 --events \ 7 --master-data=2 \ 8 --quick \ 9 <database_name> \ 10 | gzip \ 11 | blobxfer upload --storage-account-key <account_key> \ 12 --storage-url https://hoge/path/to/file \ 13 --local-path -

mysqldumpの結果をgzipで圧縮し、Azure Blob Storageに送信する動作を、
パイプで繋げております。

MySQLの認証情報は~/my.confから読み込みます。

set -o pipefailにより、パイプの途中でエラーが発生したことはわかりますが、
リモートへの送信処理が実行されてしまうと、エラーが発生した際の標準出力で上書きされてしまいます。

エラー発生時の標準出力はおそらく空データだと思っております。
(全てのエラーを把握できているわけではないので、空データが保障されるかは不明です)

環境

  • OS: Ubuntu 18.04
  • シェル: bash 4.4.20

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

エラーの時は、転送先のファイルを、開始前の状態にしておきたいということでしょうか?

blobxfer実行してしまえば、上書きされてしまうでしょうから、blobxferの実行前に食い止めるしかないですね。
blobxferの詳細は私は知らないのすが、何かオプションで救えないかは確認済みですよね?)

つまり、

Bash

1if mysql 接続だけするオプション > /dev/null #接続できるかの確認 2then mysqldump オプション | 3 gzip | 4 blobxfer オプション 5fi

でしょうか。
mysqlを実行終了して、次にmysqldumpを実行する間の瞬間で、接続数の上限に達したり、サーバーが止まったりすると駄目というリスクがありますが、まあ、ほぼゼロでしょう。

あとは、ちょっとテストする環境が無いですが、1バイト読み取るまで、blobxferを実行しないようにします。

Bash

1mysqldump オプション | 2gzip | 3( FIRSTBYTE=$(dd bs=1 count=1 status=none) 4 ( echo -n "$FIRSTBYTE"; cat ) | 5 blobxfer オプション 6)

どんな方法を取るにせよ、転送が始まって、上書きされ始めてから発生するエラーを救うのは、お書きの条件だと論理的に無理ですね。

投稿2020/02/27 17:58

otn

総合スコア84505

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hkcomori

2020/03/01 06:58

ご回答ありがとうございます。 2つ目の方法がやりたいことに近いかもと思いましたが、エラーが出て動きませんでした。 試しに次のコマンドを試してみましたが、ddは入力が0バイトでもエラーにはならないようですね。 cat <&0 | (dd bs=1 count=1 status=none && echo -n "($?)" && cat -) | cat -n > 転送が始まって、上書きされ始めてから発生するエラーを救うのは、お書きの条件だと論理的に無理 おっしゃるとおりです。 ただ、調べてみると、Azure Blob Storage側の仕様で、転送途中で接続が切れたりした場合は、その送信データを反映させない仕組みがあるそうです(後出し情報ですみません)。 エラー検出後すぐに強制終了(kill)でもしてしまえばキャンセルできないかなと期待しておりました。 ご提案頂いた若干のリスクを承知で1つ目の方法で行くか、コストを掛けてストレージを増強するか、検討いたします。 ありがとうございました。
guest

0

ローカルには中間ファイルを作成する空き容量が無い
リモートにも、以下の理由から中間ファイルを作りたくない

別アプローチですが、もしもDBが小規模で、メモリとスワップに余裕があるなら、メモリ(もしくはスワップ)上に一時ファイルを保存させる事はできます。

shell

1# メモリ/スワップ上にファイルシステムを作成 (以下、容量1024MBを指定) 2mkdir /tmp/tmpfs 3mount -t tmpfs -o size=1024m newtmp /tmp/tmpfs/ 4 5# ダンプ取得してメモリ上に保存 6mysqldump ... | gzip -c > /tmp/tmpfs/dump.gz 7 8# mysqldumpの終了ステータスが「0」ならアップロード 9if [[ $PIPESTATUS[0] == 0 ]; then 10 cat /tmp/tmpfs/dump.gz | blobxfer upload ... 11fi 12 13# ファイルシステムを破棄 14umount /tmp/tmpfs/ 15rmdir /tmp/tmpfs/

投稿2020/02/29 17:02

take88

総合スコア1351

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hkcomori

2020/03/01 06:34

空き容量がなくても、少しずつ送ってしまえば大丈夫かなという考えのもと、 パイプを使おうとしていたので、全部メモリ上に置く方法は厳しそうです。 せっかくご提案頂いたのに、すみません。。。
take88

2020/03/09 16:50

全然大丈夫ですよ。これはあくまで小規模向けの解決策ですね・・・。
guest

0

パイプで繋いだ結果が全て成功な場合のみ実行させたいのであればパイプを「&&」に置き換えてみたらどうでしょうか?

■ご参考
https://qiita.com/miyu/items/f467c3fd693b5a8d5472

投稿2020/02/28 22:48

gaccha

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2020/02/29 03:46

中間結果をファイルに保管できない(空きスペースがない)ので、駄目です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問