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

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

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

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

シェル

シェル(shell)はUnix や Linux 系のOSで使用されるコマンドインタプリタを指します。

Q&A

解決済

2回答

3142閲覧

バッククォート内のコマンドでエスケープが2つ必要である理由について

mozukku

総合スコア10

bash

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

シェル

シェル(shell)はUnix や Linux 系のOSで使用されるコマンドインタプリタを指します。

0グッド

0クリップ

投稿2020/04/25 12:40

首記の件、どうしても分からなかったので質問させてください。

環境

OS:CentOS-Stream
bashバージョン:4.4.19(1)-release (x86_64-redhat-linux-gnu)

質問内容

リモートホスト(host)に対して、以下のように特定のファイルが存在するかをSSHで確認するコマンドを作成しました。
ファイルが存在すれば0、存在しなければ1を返す単純なものです。

[root@localhost test]# ssh host "ls -l | grep -q file; echo $?" 0

この返却値を変数に格納したいと考え、以下のようにしたところ、
ファイルの存在有無にかかわらず、返却値が0となってしまいます。

[root@localhost test]# RET=`ssh host "ls -l | grep -q file; echo $?"` [root@localhost test]# echo $RET 0 [root@localhost test]# [root@localhost test]# RET=`ssh host "ls -l | grep -q file2; echo $?"` [root@localhost test]# echo $RET 0

試しに、echoで出力させる戻り値のエスケープを増やしてみたところ、正しく動作しました。

[root@localhost test]# RET=`ssh host "ls -l | grep -q file; echo \$?"` [root@localhost test]# echo $RET 0 [root@localhost test]# RET=`ssh host "ls -l | grep -q file2; echo \$?"` [root@localhost test]# echo $RET 1

ここからが質問なのですが、上記でエスケープを増やした場合に正しく動作したのは何故でしょうか?
バッククォートをつけた場合は、一度エスケープを処理する動きをするのでしょうか?

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

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

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

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

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

guest

回答2

0

ベストアンサー

そうですね。

sh

1set -v 2RET=`ssh host "ls -l | grep -q file; echo $?"`

と、コマンドを表示してみると分かりますが、サブシェルで実行されるコマンドは、

sh

1ssh host "ls -l | grep -q file; echo $?"

と、バックスラッシュが取れた状態になります。
これだと、ssh実行前にその直前のコマンドのリターンコードに展開され、リモート側にはls -l | grep -q file; echo 0の文字列が送られ、常に0が出力されます。

なので、もう一つバックスラッシュを付けるか、一重引用符で囲みます。

sh

1RET=`ssh host 'ls -l | grep -q file; echo $?'`

もしくは、

sh

1ssh host "ls -l | grep -q file" 2RET=$?

投稿2020/04/25 13:53

otn

総合スコア84531

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

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

mozukku

2020/04/25 14:22

なるほど! バッククォートで囲んだ場合はサブシェル扱いになるので、バックスラッシュが外れた状態になってしまうんですね。 だから、二重にクォートする必要がある。 最初のコマンドはカレントシェルで実行していたから上手くいったんですね。 もやもやが取れてすっきりしました。 ありがとうございます!
guest

0

あんまり詳しくないですが、(使う事が少ないので)

シェルの記述で、\ --> \ という事ですね。
エスケープ(\)一つでは、次の文字($)のエスケープしかなりません。
2つ続ける事で、シェルの文字として(\)を渡せます。

説明になってるか?

投稿2020/04/25 13:28

pepperleaf

総合スコア6383

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

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

mozukku

2020/04/25 14:32

回答ありがとうございます。 最初のコマンドではエスケープ1つで上手くいってたのに、 バックスラッシュを入れた途端エスケープ2つが必要になったので、何故だろうと不思議に思っていました。 が、バックスラッシュで実行したコマンドはサブシェル扱いになるので、 エスケープが剥ぎ取られてしまうことが分かりました。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問