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
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答4件
0
バッククォートで実行すると、サブシェルで実行されるので、外側のシェルとは別のシェエルです。シェル変数はシェルが異なると別です。
関数側で$1をechoしてみましたが引数自体が渡されていないようでした。
これはおそらく勘違い。
Bash
1function test_func(){ 2 test_var=$1 3 echo ARG is $1 >&2 4}
のように標準出力以外にechoしましたか?標準出力はバッククォートに取られますよ。
やりたいことを書いてもらうと、アドバイスが出来るかもしれません。
投稿2017/03/20 14:44
総合スコア86295
0
バッククォートや$()、evalでスクリプトファンクションを実行すると、forkされて実行されます。
その中で使われた変数は、上位からは参照ができない事に寄るものと思います。
上位に返す場合は、echoで戻すことがきます。
関数側で$1をechoしてみましたが引数自体が渡されていないようでした。
sh
1function test_func(){ 2echo $1 3} 4 5if [ "`test_func test`" == 'test' ]; then echo success ;fi 6success
渡たされると思います。
投稿2017/03/20 22:47
総合スコア4070
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
ベストアンサー
シェルで$varなどとして参照できる変数には2種類の意味合いの物があります。
- 環境変数以外の変数
シェルが内部的に管理する変数です。同一のシェルプロセスの中でのみ参照・設定ができますが親プロセスや子供プロセスの変数の参照・設定はできません。
- 環境変数
unix系OSの仕様で「親プロセスから子供プロセスへ引き継ぐことを目的にプロセスのメモリー空間内に保存された名前,値の組の情報」として決まっているものです。これはプロセスイメージ(メモリーの中身)が決まるとき、親プロセスの内容が引き継がれます(execvpeシステムコールを使うと引き継がずに異なる環境変数を明示できますが)。
bashでは環境変数でない変数を環境変数に昇格(?)することがexportにより行えます。しかしexportといっても子供プロセスへ引き継げるだけであって親プロセスへは反映できません。
要するに上の二つの変数のいずれも子供プロセスから親プロセスの変数の書き換えはできません。
testはビルトインコマンドなので子供プロセスではなく現在のシェルプロセス内で実行されます。ただしtestには引数を評価する能力はないので、関数呼び出しをtestの引数部分に直接書きたいならバッククォート構文を使うしか手がありませんが、他の方の回答にあるようにバッククォート構文は子プロセスで実行されるため関数は実行できても関数内で行った変数の変更は意味を失います。
このようにシェル上で使えるコマンドや構文には子供プロセスを生成してそこで実行されるものと子供プロセスを生成せずに元のシェルプロセス内で実行されるものがあります。前者には変数の参照・設定, 関数の定義・呼び出し, test/cd/if/case/forなどのビルトインコマンド, { ... }などがありますし、後者はビルトインコマンド以外のコマンド, バッククォート構文, ( ... )などがあります。シェルスクリプトを記述する際にはそれらの違いをきちんと把握しておくと混乱を避けることができると思います。
if文内に引数付きの関数を正常に実行する方法
ifと関数呼び出しを組み合わせて使うには
- ifより以前に関数を呼び出す
if文内での実行にはなりませんので解にはなりませんね
- シェルのバッククォート構文などでtestを起動する前に引数置換をさせる
ifに限らず任意の場所で使えるわけですが子供プロセスで実行されるため関数から呼び出し元へ返すことのできる情報はプロセスのリターンステータス、標準出力に限定されます。
- 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 04:21
編集2017/03/21 05:50総合スコア18404
0
たぶん
$ (test_func test)
ってやっても同様に test_var には設定されないと思いますが、
バッククオートを使った場合も同様の現象なのかなあ。
つまり、別プロセスで処理されるので、現在のプロセスには
影響を与えられない、と。
というか、関数内で設定したものが外に影響するって話が
「えー!そうなの!?」って感想でした。
ちなみに、なにをしたいのかがよく分かりません。(^_^;
投稿2017/03/20 14:22
総合スコア7468
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/03/21 23:29
2017/03/22 02:26