1. 概要

Linuxでシェルスクリプトを作成する場合、シェルスクリプトの実行中に、ディレクトリを切り替えたり、他のスクリプトやプログラムを実行したりする必要がある場合があります。

このチュートリアルでは、シェルスクリプトの別のディレクトリからスクリプトまたはプログラムを実行する方法を見ていきます。 依存関係を正しく満たすには、コンテキストの現在のディレクトリを追跡する必要があります。

次のセクションで、この問題をどのように処理できるかを確認します。

2. 問題

異なるディレクトリに配置されたスクリプトがいくつかあるとしましょう。

$ tree .
.
├── init
│   ├── init.conf
│   └── init.sh
├── run.sh
└── start.sh

1 directory, 4 files

ここに、[X21X]run.shとinit.shを呼び出すstart.shがあります。

$ cat init/init.conf 
NAME=Baeldung
$
$ cat init/init.sh 
#!/bin/bash
. init.conf
echo $NAME
$
$ cat run.sh 
#!/bin/bash
echo "Running script"

ご覧のとおり、init.shスクリプトはinitディレクトリ内に保持されています。 このような状況では、他のスクリプト呼び出しが正しく機能するように、ディレクトリをstart.shから正しく変更する必要があります。

シェルスクリプトでディレクトリを変更するについてはすでに説明しましたが、この記事では、異なる呼び出し間で元のコンテキストを維持することに焦点を当てます。

これを行うさまざまな方法を見てみましょう。

3. 変数の使用

最初の最も簡単な解決策は、現在のディレクトリを変数に保存し、新しいディレクトリに切り替えることです。 スクリプトを実行した後、変数を使用してディレクトリを古いディレクトリに復元できます。

$ cat start.sh 
#!/bin/bash
CUR_DIR=$(pwd)
cd init
./init.sh
cd $CUR_DIR
echo "Starting script"
./run.sh
$
$ ./start.sh 
Baeldung
Starting script
Running script

上記のスクリプトでは、 pwd コマンドを使用して現在のディレクトリをキャプチャし、それを変数CUR_DIRに保存しました。 init.sh を実行した後、CUR_DIRに保存されている古いディレクトリに戻ります。

出力から、 init.sh から名前が正しく出力され、s tart.shおよびからechoステートメントも出力されたことがわかります。 ]run.shスクリプト。

4. 変数を使用せずに

上記のソリューションでは、変数を使用して現在のディレクトリを格納しました。 ただし、‘cd-‘ コマンドを使用して前のディレクトリに移動すると、中間変数を作成しなくても同じ結果を得ることができます。

$ cat start.sh 
#!/bin/bash
cd init
./init.sh
cd -
echo "Starting script"
./run.sh
$
$ ./start.sh 
Baeldung
/home/bluelake/Documents/shell/chdir
Starting script
Running script

ここで、‘cd-‘コマンドを呼び出すと、ディレクトリが古いディレクトリに変更されます。 init.sh は子プロセスとして実行されるため、init.sh内のディレクトリを変更してもこれは機能します。

これに伴う問題は、 ‘CD -‘ コマンドが実行され、 新しいディレクトリをstdoutにエコーします。 これを抑制する必要がある場合、これを行うには2つの方法があります

1つの方法は、出力をnullデバイスにリダイレクトすることです。

cd - > /dev/null

もう1つは、Bash内部変数$OLDPWDを使用することです。

cd $OLDPWD

変数を作成せずに結果を達成したとしても、コードのさらに下にこの変数が必要かどうかに応じて、これが本当に何かを節約しているかどうかを検証します。

5. サブシェルで実行

別の解決策は、サブシェルからinit.shスクリプトを実行することです。 start.shでこれを行う方法を見てみましょう。

$ cat start.sh 
#!/bin/bash
(cd init; ./init.sh)
echo "Starting script"
./run.sh
$
$ ./start.sh 
Baeldung
Starting script
Running script

サブシェルでコマンドを呼び出す必要がある場合は、括弧で囲みます。 したがって、ディレクトリを変更した後、init.shスクリプトがサブシェル内で呼び出されていることがわかります。 このように、は現在のシェルに影響を与えることなく個別に実行されます。

ここでは、initディレクトリが常に存在すると想定しています。 ただし、ディレクトリがわからない場合があります。 このような場合、論理AND演算子を使用して、init.shスクリプトが呼び出されないようにすることができます。

(cd init && ./init.sh)

これにより、スクリプトを実行する前に、initディレクトリが存在することを確認します。

6. pushdコマンドの使用

pushdを使用してこの問題を解決する方法を見てみましょう。

$ cat start.sh 
#!/bin/bash
pushd init
./init.sh
popd
echo "Starting script"
./run.sh
$
$ ./start.sh 
~/Documents/shell/chdir/init ~/Documents/shell/chdir
Baeldung
~/Documents/shell/chdir
Starting script
Running script

上記のスクリプトでは、pushdおよびpopdコマンドを使用してディレクトリを切り替えました。 ご存知のように、 pushdは現在のディレクトリを保存し、引数として指定された新しいディレクトリに切り替えます。 その後、 popdを使用して、プッシュされたディレクトリを復元できます。

結果から、すべてが正常に機能していることがわかります。

pushdおよびpopdコマンドからの出力を抑制するために、これらを / dev /nullデバイスにリダイレクトできます。

pushd init > /dev/null
./init.sh
popd > /dev/null

7. shコマンドの使用

最後に、 sh コマンドを使用して別のプロセスで実行し、現在のシェルに影響を与えないようにすることができます。

$ cat start.sh 
#!/bin/bash
sh -c 'cd init && ./init.sh'
echo "Starting script"
./run.sh
$
$ ./start.sh 
Baeldung
Starting script
Running script

ご覧のとおり、shコマンドの引数としてコマンドを渡しました。 上記の結果から、正しく実行されていることがわかります。 ただし、これは、サブシェルを使用してinit.shスクリプトを実行した以前のアプローチと同様です。

8. 結論

このチュートリアルでは、現在のシェルに影響を与えずにディレクトリを変更してスクリプトを実行するいくつかの異なる方法を見てきました。 これらのうち、サブシェルを使用する方法がこの問題の最良の解決策であることがわかります。