web-dev-qa-db-ja.com

シェルスクリプトを実行するさまざまな方法

スクリプトを実行する方法はいくつかありますが、私が知っている方法は次のとおりです。

/path/to/script # using the path (absolute or relative)
. script        # using the . (dot)
source script   # using the `source` command

これ以上ですか?それらの違いは何ですか?使用しなければならない状況はありますか?

44
phunehehe

もう1つの方法は、インタープリターを呼び出してスクリプトへのパスを渡すことです。

/bin/sh /path/to/script

ドットとソースは同等です。 (編集:いいえ、そうではありません:KeithBが別の回答のコメントで指摘しているように、「。」はbash関連のシェルでのみ機能し、「source」はbash関連のシェルとcsh関連のシェルの両方で機能します。 -place(スクリプトをすぐにコピーして貼り付けたかのように)。つまり、スクリプト内の関数と非ローカル変数はそのまま残ります。また、スクリプトがディレクトリにcdを実行した場合でも、完了した時点でそこにいます。

スクリプトを実行する他の方法では、独自のサブシェルでスクリプトを実行します。スクリプトの変数は、完了してもまだ有効ではありません。スクリプトがディレクトリを変更した場合、呼び出し環境には影響しません。

/ path/to/scriptと/ bin/shスクリプトは少し異なります。通常、スクリプトの先頭には次のような「シバン」があります。

#! /bin/bash

これはスクリプトインタープリタへのパスです。実行時に指定したインタープリターとは異なるインタープリターを指定すると、動作が異なる(またはまったく機能しない)場合があります。

たとえば、PerlスクリプトとRubyスクリプトは(それぞれ)で始まります:

#! /bin/Perl

そして

#! /bin/Ruby

/bin/sh scriptを実行してこれらのスクリプトの1つを実行すると、スクリプトはまったく機能しなくなります。

Ubuntuは実際にはbashシェルを使用していませんが、ダッシュと呼ばれる非常によく似たシェルを使用しています。ダッシュインタープリタを使用してbashスクリプトを呼び出したばかりなので、/bin/sh scriptを実行して呼び出すと、bashを必要とするスクリプトがわずかに正しく機能しない場合があります。

スクリプトを直接呼び出すこととスクリプトパスをインタープリターに渡すことのもう1つの小さな違いは、スクリプトを直接実行するには実行可能としてマークする必要がありますが、パスをインタープリターに渡して実行する必要はありません。

別のマイナーバリエーション:スクリプトを実行するこれらの方法の前にevalを付けることができるので、

eval sh script
eval script
eval . script

等々。実際には何も変わりませんが、念のため入れてみようと思いました。

32
Shawn J. Goff

ほとんどの人は、次の debuging flags をスクリプトに追加して、シェルスクリプトをデバッグします。

set -x     # Print command traces before executing command.
set -v     # Prints Shell input lines as they are read.
set -xv    # Or do both

ただし、これは、エディターでファイルを開き(ファイルを編集する権限がある場合)、set -xのような行を追加し、ファイルを保存して、ファイルを実行する必要があることを意味します。次に、完了したら、同じ手順に従ってset -xなどを削除する必要があります。これは退屈な作業です。

すべてを行う代わりに、コマンドラインでデバッグフラグを設定できます。

$ bash -x ~/bin/ducks
+ du -cks -x dir1 dir2 dir3 file1 file2 file3
+ sort -n
+ tail .ducks
123 etc
424 bin
796 total



$ sh -xv ~/bin/ducks  
#!/usr/bin/env bash

# Find the disk hog
# Borrowed from http://oreilly.com/pub/h/15
...
...
9

Shawn J. Goffは多くの良い点を述べましたが、全体の話は含まれていませんでした:

Ubuntuは実際にはbashシェルを使用していませんが、ダッシュと呼ばれる非常によく似たシェルを使用しています。ダッシュインタープリターを使用してbashスクリプトを呼び出したばかりなので、bashを必要とするスクリプトは、/bin/shスクリプトを実行して呼び出すとわずかに正しく機能しない場合があります。

多くのシステムスクリプト(init.d、/ etcなど)にはシバン#!/bin/shがありますが、/bin/shは、実際には別のシェルへのシンボリックリンクです-以前は/bin/bash、最近は/bin/dash。ただし、そのうちの1つが/bin/shとして呼び出されると、動作が異なります。つまり、POSIX互換モードに固執します。

彼らはこれをどのように行うのですか?まあ、彼らは彼らが呼び出された方法を検査します。

シェルスクリプト自体がそれがどのように呼び出されたかをテストし、それに応じてさまざまなことを行うことができますか?はい、できます。したがって、それを呼び出す方法は常に異なる結果につながる可能性がありますが、もちろん、あなたを困らせることはめったにありません。 :)

経験則として、bashのような特定のシェルを学び、bashチュートリアルからコマンドを書く場合は、特に明記されていない限り、#!/bin/bashではなく#!/bin/shを見出しに入れてください。そうしないと、コマンドが失敗する可能性があります。また、スクリプトを自分で記述していない場合は、シェル(./foo.shbar/foo.sh)を推測する代わりに、スクリプトを直接(sh foo.shsh bar/foo.sh)呼び出します。シバンは適切なシェルを呼び出す必要があります。

そして、他に2種類の呼び出しがあります。

cat foo.sh | dash
dash < foo.sh
7
user unknown

.sourceは、サブプロセスを生成せず、現在のシェルでコマンドを実行するという点で同等です。これは、スクリプトが環境変数を設定したり、現在の作業ディレクトリを変更したりするときに重要です。

パスを使用するか、それを/bin/shに与えると、コマンドが実行される新しいプロセスが作成されます。

5
mouviciel
sh script
bash script

まだあるかな….

.sourceは同じです。実行後、scriptの環境の変更は保持されます。通常、これはBashライブラリのソースとして使用されるため、ライブラリは多くの異なるスクリプトで再利用できます。

また、現在のディレクトリを保持するための良い方法です。スクリプトでディレクトリを変更した場合、そのスクリプトを実行するシェルには適用されません。しかし、それを実行するためにそれを調達した場合、スクリプトが終了した後、現在のディレクトリが保持されます。

2
livibetter

。とソースは、少なくともzshでは少し異なります(それが私が使用するものです)。

source file

仕事中

. file

必要ではない

. ./file
1
bollovan
. ./filename
# ( dot space dot slash filename )

ディレクトリがパスにない場合、現在のシェルでスクリプトを実行します。

1
jrh_enginnering

" serland exec "は別の方法としてカウントされますか?ユーザーランドexecはコードをロードし、execve()システムコールを使用せずにコードを実行します。

1
Bruce Ediger