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

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

ただいまの
回答率

92.04%

  • Linux

    1849questions

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

if文の条件式に関数を入れると引数が渡されない

解決済

回答 4

投稿 2017/03/20 22:49

  • 評価
  • クリップ 0
  • VIEW 118

soich

score 92

LinuxのBashシェル上で自前の関数を作成してif文の条件式にその関数を
引数付きで記述すると引数が反映されていない結果になってしまいます。

~/.bashrc(自前の関数を定義)

#!/bin/bash
function test_func(){
    test_var=$1
}

関数を普通に実行

$ test_func test
$ echo $test_var
test


「test_var」に引数が代入されている

if文内にtest_funcを指定して実行

$ unset test_var
$ if [ "`test_func test`" = '' ]; then echo success ;fi
$ echo $test_var
// 何も表示されない


関数側で$1をechoしてみましたが引数自体が渡されていないようでした。
if文内に引数付きの関数を正常に実行する方法など教えていただけますと幸いです・・・

よろしくお願いいたしますmm

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

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

    クリップした質問はマイページの「クリップ」タブからいつでも見ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+3

バッククォートで実行すると、サブシェルで実行されるので、外側のシェルとは別のシェエルです。シェル変数はシェルが異なると別です。

関数側で$1をechoしてみましたが引数自体が渡されていないようでした。 

これはおそらく勘違い。

function test_func(){
    test_var=$1
    echo ARG is $1 >&2
}


のように標準出力以外にechoしましたか?標準出力はバッククォートに取られますよ。

やりたいことを書いてもらうと、アドバイスが出来るかもしれません。

投稿 2017/03/20 23:44

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    以下のような回答は評価を下げられます

    • 間違っている回答
    • 質問の回答になっていない投稿
    • 不快な投稿

    評価を下げる際はその理由をコメントに書き込んでください。

  • 2017/03/22 08:29

    ご回答ありがとうございました。引数渡されないの勘違いでした;
    友人からif文内で引数渡されないと聞かれたので、どうして渡せないのかと思い質問させていただきました。

    キャンセル

  • 2017/03/22 11:26

    なるほど。自分の問題ではなかったのですね。
    「渡せないはずは無い」と考えるのが大事です。

    キャンセル

+1

バッククォートや$()、evalでスクリプトファンクションを実行すると、forkされて実行されます。
その中で使われた変数は、上位からは参照ができない事に寄るものと思います。
上位に返す場合は、echoで戻すことがきます。

関数側で$1をechoしてみましたが引数自体が渡されていないようでした。

function test_func(){
echo $1
}

if [ "`test_func test`" == 'test' ]; then echo success ;fi
success

渡たされると思います。

投稿 2017/03/21 07:47

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    以下のような回答は評価を下げられます

    • 間違っている回答
    • 質問の回答になっていない投稿
    • 不快な投稿

    評価を下げる際はその理由をコメントに書き込んでください。

  • 2017/03/22 08:27

    渡されていました・・・すみません;
    echoで渡せばいいのですね。ありがとうございます。
    上の方とベストアンサー迷ったのですが、、評価+1させていただきますmm

    キャンセル

checkベストアンサー

0

シェルで$varなどとして参照できる変数には2種類の意味合いの物があります。

  • 環境変数以外の変数
    シェルが内部的に管理する変数です。同一のシェルプロセスの中でのみ参照・設定ができますが親プロセスや子供プロセスの変数の参照・設定はできません。

  • 環境変数
    unix系OSの仕様で「親プロセスから子供プロセスへ引き継ぐことを目的にプロセスのメモリー空間内に保存された名前,値の組の情報」として決まっているものです。これはプロセスイメージ(メモリーの中身)が決まるとき、親プロセスの内容が引き継がれます(execvpeシステムコールを使うと引き継がずに異なる環境変数を明示できますが)。
    bashでは環境変数でない変数を環境変数に昇格(?)することがexportにより行えます。しかしexportといっても子供プロセスへ引き継げるだけであって親プロセスへは反映できません。

要するに上の二つの変数のいずれも子供プロセスから親プロセスの変数の書き換えはできません。

testはビルトインコマンドなので子供プロセスではなく現在のシェルプロセス内で実行されます。ただしtestには引数を評価する能力はないので、関数呼び出しをtestの引数部分に直接書きたいならバッククォート構文を使うしか手がありませんが、他の方の回答にあるようにバッククォート構文は子プロセスで実行されるため関数は実行できても関数内で行った変数の変更は意味を失います。

このようにシェル上で使えるコマンドや構文には子供プロセスを生成してそこで実行されるものと子供プロセスを生成せずに元のシェルプロセス内で実行されるものがあります。前者には変数の参照・設定, 関数の定義・呼び出し, test/cd/if/case/forなどのビルトインコマンド, { ... }などがありますし、後者はビルトインコマンド以外のコマンド, バッククォート構文, ( ... )などがあります。シェルスクリプトを記述する際にはそれらの違いをきちんと把握しておくと混乱を避けることができると思います。

if文内に引数付きの関数を正常に実行する方法

ifと関数呼び出しを組み合わせて使うには

  1. ifより以前に関数を呼び出す
    if文内での実行にはなりませんので解にはなりませんね

  2. シェルのバッククォート構文などでtestを起動する前に引数置換をさせる
    ifに限らず任意の場所で使えるわけですが子供プロセスで実行されるため関数から呼び出し元へ返すことのできる情報はプロセスのリターンステータス、標準出力に限定されます。

  3. testを使わずifに続けて直接呼び出す
    ifはtestと組み合わせることが多いですが任意のコマンドや関数も使えます。その一方でtestが提供する条件式は使えなくなります。子供プロセスでは実行されないため、関数が呼び出し元へ戻せる情報は「変数更新・入出力などの副作用、関数のリターンステータス」になりますがリターンステータスをif文の分岐条件として使うことになります。リターンステータスは「子供プロセスで実行されない」ため、exitではなくreturnで返すことに注意します。exitとするとif文の条件判定の途中でシェルプロセスが終了してしまいますw;

function test_func() {
  RTN="$1$1"
  case $1 in
  case a) return 0;;
  case *) return 1;;
  esac
}

if test_func a; then
  echo "true and RTN=$RTN"
fi

==> 実行すると...
true and RTN=aa

しかし関数が「何かの判定をする」機能と「変数を更新する」機能をごっちゃに持ってしまうためなんとなくパラノイアぎみのスクリプトに見えます。とはいえ、シェルスクリプトは手早く短くやりたいことができればいいと考えることも多いので「きれいかどうか」は二の次と言えるかもしれませんね。


補足:蛇足とは思いますが・・・
自分の回答に書いた「子プロセス」とか、他のみなさんが使っておられる言葉「別のシェル」「forkされて実行される」あるいはman bashで使われている「サブシェル」は同様の意味合いです。プロセスはそれぞれが独立したメモリー空間になるのでメモリー空間上に存在するシェル変数等もまたそれぞれ独立して存在しているという点がポイントと思います。

投稿 2017/03/21 13:21

編集 2017/03/21 14:50

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    以下のような回答は評価を下げられます

    • 間違っている回答
    • 質問の回答になっていない投稿
    • 不快な投稿

    評価を下げる際はその理由をコメントに書き込んでください。

  • 2017/03/22 08:26

    細かい部分までご説明いただきありがとうございました!

    キャンセル

0

たぶん

$ (test_func test)


ってやっても同様に test_var には設定されないと思いますが、
バッククオートを使った場合も同様の現象なのかなあ。
つまり、別プロセスで処理されるので、現在のプロセスには
影響を与えられない、と。
というか、関数内で設定したものが外に影響するって話が
「えー!そうなの!?」って感想でした。
ちなみに、なにをしたいのかがよく分かりません。(^_^;

投稿 2017/03/20 23:22

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    以下のような回答は評価を下げられます

    • 間違っている回答
    • 質問の回答になっていない投稿
    • 不快な投稿

    評価を下げる際はその理由をコメントに書き込んでください。

  • 2017/03/22 08:30

    友人からif文内で引数渡されないと聞かれたので、どうして渡せないのかと思い質問させていただいた次第です。

    キャンセル

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

ただいまの回答率

92.04%

関連した質問

同じタグがついた質問を見る

  • Linux

    1849questions

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

閲覧数の多いLinuxの質問