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

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

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

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

Q&A

解決済

4回答

14264閲覧

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

soich

総合スコア176

Linux

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

0グッド

0クリップ

投稿2017/03/20 13:49

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ページで確認できます。

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

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

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

guest

回答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

otn

総合スコア84505

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

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

soich

2017/03/21 23:29

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

2017/03/22 02:26

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

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

A.Ichi

総合スコア4070

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

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

soich

2017/03/21 23:27

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

0

ベストアンサー

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

  • 環境変数以外の変数

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

  • 環境変数

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

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

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

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

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

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

  1. ifより以前に関数を呼び出す

if文内での実行にはなりませんので解にはなりませんね

  1. シェルのバッククォート構文などでtestを起動する前に引数置換をさせる

ifに限らず任意の場所で使えるわけですが子供プロセスで実行されるため関数から呼び出し元へ返すことのできる情報はプロセスのリターンステータス、標準出力に限定されます。

  1. 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
KSwordOfHaste

総合スコア18394

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

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

soich

2017/03/21 23:26

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

0

たぶん

$ (test_func test)

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

投稿2017/03/20 14:22

takasima20

総合スコア7458

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

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

soich

2017/03/21 23:30

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問