Bashでは、いつエイリアスを作成し、いつスクリプトを作成し、いつ関数を作成するのですか?


360

この質問をするのに、ほぼ10年間のLinuxの使用が必要でした。それはすべて試行錯誤とランダムな深夜インターネットサーフィンでした。

しかし、人々はこのために10年を必要としないはずです。Linuxを使い始めたばかりの場合、知りたいのは、エイリアスを作成するタイミング、スクリプトを作成するタイミング、関数を作成するタイミングです。

エイリアスに関しては、引数をとらない非常に簡単な操作にエイリアスを使用します。

alias houston='cd /home/username/.scripts/'

それは明らかです。しかし、これを行う人もいます:

alias command="bash bashscriptname"

(そして.bashrcファイルに追加します)

それをする正当な理由はありますか?私は一生懸命努力していますが、それをやりたいと思う状況はまったく考えられません。それで、それが違いを生むエッジケースがあるならば、以下に答えてください。

それが、私が自分のPATHとchmod +xそれに何かを入れる場所だからです。

次のトピックに進みます。例えば、私は、隠しフォルダ(追加.scripts/ちょうど私に行を追加することで、私のPATHにホームディレクトリ内の).bashrcPATH=$PATH:/home/username/.scripts/)ので、そこに実行可能なものは自動的に自動的に補完します。

必要な場合。

私は本当にそれを必要としませんが、私は?Pythonのようなシェルではない言語に対してのみ使用します。

それがシェルの場合、まったく同じ内部に関数を書くことができます.bashrc

funcname () {
  somecommand -someARGS "$@"
}

私が述べたように、私は試行錯誤を通してこれの多くを見つけました。そして、私のコンピューターが死んだときだけ、機能の美しさを本当に見ました。そして、彼らが使用していないとき、私は周りの人々のコンピューターを使用せざるを得ませんでした。

スクリプトのディレクトリ全体をコンピューターからコンピューターに移動する代わりに、他のすべての.bashrcを自分のものに置き換えるだけになりました。

しかし、私は何かを見逃しましたか?

それでは、エイリアスを作成するタイミング、スクリプトを作成するタイミング、関数を作成するタイミングについて、初心者のLinuxユーザーに何を伝えますか?

明らかでない場合、これに答える人々は3つのオプションすべてを利用すると仮定しています。エイリアスのみを使用する、スクリプトのみを使用するか、関数のみを使用する場合、またはエイリアスとスクリプト、またはエイリアスと関数、またはスクリプトと関数のみを使用する場合、この質問は実際には対象ではありません。


5
可能性のある重複スクリプトVS bashの機能
ジル・

10
この質問の目的ではない{alias、script、function}のすべてのサブセットを明示的に述べるための+1。ヌルサブセットを省略してもかまわないという子供らしい信仰の場合は+1。
トーマスL Holaday

1
この質問では具体的にbashについて尋ねましたが、古いBourneシェルには「エイリアス」がありましたが、機能はありませんでした。互換性を心配している場合、これは違いをもたらすかもしれません。
AndyB

これに対して.bashrcが本当に最高の場所、または少なくとも堅実な場所である場合は?Linuxで同じことを行う方法は非常に多くありますが、すべてが同じであり、最も一般的な方法で行うことを好みます。
キット

回答:


242

エイリアスは(一般に)コマンドのデフォルトオプションを変更する以上のことを効果的に行うべきではありません。コマンド名の単純なテキスト置換にすぎません。引数では何もできませんが、実際に実行するコマンドに引数を渡します。したがって、1つのコマンドの前に引数を追加するだけでよい場合は、エイリアスが機能します。一般的な例は

# Make ls output in color by default.
alias ls="ls --color=auto"
# make mv ask before overwriting a file by default
alias mv="mv -i"

エイリアスよりも複雑なことをする必要があるが、それ自体では役に立たない場合は、関数を使用する必要があります。たとえば、パイプラインにあるかどうかに応じてのデフォルトの動作を変更することについて私が尋ねた質問に対して、この回答を受け取りgrepます。

grep() { 
    if [[ -t 1 ]]; then 
        command grep -n "$@"
    else 
        command grep "$@"
    fi
}

エイリアスには複雑すぎるため(条件に基づいて異なるデフォルトを必要とする)、関数の完璧な例ですが、非対話型スクリプトでは必要なものではありません。

あまりにも多くの関数または関数が大きすぎる場合は、それらを隠しディレクトリの個別のファイルに配置し、次の場所に配置します~/.bashrc

if [ -d ~/.bash_functions ]; then
    for file in ~/.bash_functions/*; do
        . "$file"
    done
fi

スクリプトは独立している必要があります。再利用できるもの、または複数の目的に使用できるものとして価値があるはずです。


14
また、.またはでソースされていない限りsource、スクリプトは個別のbashプロセスによって実行され、独自の環境を持っていることを覚えておくことが重要です。このため、シェル環境を変更するもの(関数、変数など)は、スクリプトを実行したシェル環境に保持されません。
ウィルVousden

260

他の回答は、個人の好みに基づいたいくつかのソフトな一般的なガイドラインを提供しますが、スクリプト、関数、またはエイリアスを決定する際に考慮すべき多くの関連する事実を無視します。

エイリアスと関数¹

  • エイリアスと関数の内容全体がシェルのメモリに保存されます。
  • これの自然な結果はエイリアスであり、関数は現在のシェルでのみ使用でき、テキストエディター、スクリプト、または同じシェルの子インスタンスなど、シェルから呼び出すことができる他のプログラムでは使用できません。
  • エイリアスと関数は現在のシェルによって実行されます。つまり、それらはシェルの現在の環境内で実行され、シェルの現在の環境に影響を与えます。²エイリアスまたは関数を実行するのに別のプロセスは必要ありません。

スクリプト

  • シェルはスクリプトをメモリに保持しません。代わりに、スクリプトは必要なたびに保存されているファイルから読み取られます。$PATH検索によってスクリプトが見つかった場合、多くのシェルはパス名のハッシュをメモリに保存して、将来の$PATHルックアップの時間を節約しますが、それは使用していないときのスクリプトのメモリフットプリントの範囲です。
  • スクリプトは、関数やエイリアスよりも多くの方法で呼び出すことができます。これらは、などのインタープリターに引数として渡すことができますsh script。または、実行可能ファイルとして直接呼び出すこともできます。この場合、シェバン行のインタープリター(例:)を#!/bin/sh呼び出して実行します。どちらの場合も、スクリプトは、シェルの環境とは別の独自の環境を備えた別個のインタープリタープロセスによって実行されます。シェルの環境は、スクリプトの影響を一切受けません。実際、インタープリターシェルは呼び出しシェルと一致する必要さえありません。この方法で呼び出されたスクリプトは、通常の実行可能ファイルのように動作するように見えるため、どのプログラムでも使用できます。

    最後に、スクリプトは.、を使用して、または一部のシェルで、現在のシェルで読み取って実行できますsource。この場合、スクリプトは、常にメモリに保持されるのではなく、オンデマンドで読み取られる関数のように動作します。

応用

上記を考慮すると、何かをスクリプトにするか、関数/エイリアスにするかについて、いくつかの一般的なガイドラインを思いつくことができます。

  • シェル以外の他のプログラムで使用できる必要がありますか? もしそうなら、それはスクリプトでなければなりません。

  • 対話型シェルからのみ利用できるようにしますか? 外部コマンド/スクリプトに影響を与えずに対話的に実行する場合、多くのコマンドのデフォルトの動作を変更するのが一般的です。この場合、シェルの「対話モード専用」rcファイルに設定されたエイリアス/関数を使用します(bashこれはです.bashrc)。

  • シェルの環境を変更する必要がありますか? 関数/エイリアスまたはソーススクリプトの両方を選択できます。

  • よく使うものですか? メモリ内に保持する方がおそらく効率的であるため、可能であれば関数/エイリアスにします。

  • 逆に、めったに使用しないものですか? その場合、必要のないときにメモリを占有する意味はないので、スクリプトにします。


¹関数とエイリアスにはいくつかの重要な違いがありますが、関数はエイリアスができることをすべて実行できるため、それらはグループ化されます。エイリアスはローカル変数を持つことも、引数を処理することもできません。また、1行より長いものには不便です。

²Unixシステムで実行されているすべてのプロセスには、デフォルトのロケールや実行可能な検索パスの指定など、グローバル構成設定が含まれていることが多いペアで構成される環境がありますvariable=valueLANGPATH


26
私見これは最良の答えです。
リュックM

4
質問/回答の形式は素晴らしいアイデアです。私はそれを盗むかもしれません。;
ミケル

4
注目に値する:2つ(またはそれ以上)のスクリプトが何らかのコードを共有する必要がある場合、それらのスクリプトの両方がインポート/ソースする3番目のファイルにある関数にそのコードを配置するのがおそらく最善です。
kbolino

3
質問のリストに追加する別の項目:コマンドの機能をその場で変更する必要がありますか?スクリプトへの変更はすべてのセッションに反映されますが、関数とエイリアスはセッションごとにリロードまたは再定義する必要があります。
Stratus3D

3
いい答えだ。もう1つ重要なこと(私にとって):他のユーティリティへの「ショートカット」を作成する場合、既存のオートコンプリートはエイリアスのみで機能しますが、スクリプトまたは関数では機能しないため、エイリアスを使用する方が良いです(エイリアスの場合は+1)。たとえばalias g='gradle'gエイリアスを使用するとgradleオートコンプリートを取得しますが、スクリプトgradle $*または関数を使用するとすぐに取得できませんgradle $@
Yoav Aharoni

37

それは各人の好み次第だと思います。私にとって、ロジックは次のようになります。

  • 最初にエイリアスを作成します。これは最も簡単だからです。
  • 物が複雑すぎて1行に収まらない場合は、関数にしようとしています。
  • 関数が数十行を超えて大きくなり始めたら、スクリプトに入れます。

何かやってからあなたを制限するためには何も本当にありません動作しますが


6
私は頻繁に関数オプションをスキップし、すぐにスクリプトを作成します。しかし、私は、それは、部分的に好みの問題であることに同意
ベルンハルト

2
関数は、いくつかのスクリプトで必要な場合に意味を持ち始めます。
ニルス

7
...または、現在のシェルを変更するために副作用が必要な場合。
グレンジャックマン

理にかなっています、男!
エクスプローラー

15

少なくとも部分的には個人的な好みの問題です。一方、いくつかの明確な機能的区別があります。

  • エイリアス:単純なテキストの置換にのみ適し、引数/パラメーターはありません
  • 機能:記述/使用が簡単、完全なシェルスクリプト機能、bash内でのみ使用可能
  • スクリプト:多かれ少なかれ関数に似ていますが、bash以外でも利用可能(呼び出し可能)

シェルスクリプトを見ると、ここ数年でエイリアスを書くのをやめました(それらはすべて時間が経つにつれて関数に成長する傾向があるためです)。

PS:alias command="bash bashscriptname"私は実際にこれを行う理由がわかりません。bashscriptname$ PATHにない場合でも、単純なalias c=/path/to/scriptもので十分です。


1
alias command="bash bashscriptname"スクリプト必ずしも実行可能である必要はありません。でするalias c=/path/to/script必要があります。
マーティン

関数が「Bash内でのみ使用可能」であることはまったくありません。Bashのみの機能であると言うのであれば、それは単純に偽です(Bourneシェルと互換性のあるすべての派生物に含まれています)。そして、それらがインタラクティブシェルの機能であると言うのであれば、それも正確ではありません(ただし、エイリアス、変数、および関数は、インタラクティブシェルによって起動時に読み込まれるファイルで定義され、明らかに非インタラクティブシェルによって読み込まれません)。
トリプリー

@tripleee意味は「exec()関数をシェル化することはできません」に似てい
nohillside

11

エイリアスと関数に関する追加のポイントを次に示します。

  • 同じ名前のエイリアスと関数は共存できます
  • エイリアス名前空間が最初に検索されます(最初の例を参照)
  • エイリアス、サブシェルまたは非対話型環境で設定することはできません(2番目の例を参照)

例えば:

alias f='echo Alias'; f             # prints "Alias"
function f { echo 'Function'; }; f  # prints "Alias"
unalias f; f                        # prints "Function"

ご覧のとおり、エイリアスと関数には個別の名前空間があります。詳細はdeclare -A -p BASH_ALIASESand を使用して見つけることができdeclare -f f、定義を出力します(両方ともメモリに保存されます)。

エイリアスの制限を示す例:

alias a='echo Alias'
a        # OK: prints "Alias"
eval a;  # OK: prints "Alias"
( alias a="Nested"; a );  # prints "Alias" (not "Nested")
( unalias a; a );         # prints "Alias"
bash -c "alias aa='Another Alias'; aa"  # ERROR: bash: aa: command not found

ご覧のとおり、エイリアスは関数とは異なり、ネストできません。また、それらの使用法は対話型セッションに限定されます。

最後に、次のように、関数をすぐに呼び出すように宣言することにより、エイリアスで任意の計算を行えることに注意してください。

alias a_complex_thing='f() { do_stuff_in_function; } f'

Gitエイリアスの場合、すでに広く使用されています。関数を宣言するよりもそうすることの利点は.、同じ名前の関数を宣言するスクリプトをソース化する(または使用する)ことによってエイリアスを単純に上書きできないことです。


10

スクリプトを記述するタイミング...

  • スクリプトは、ソフトウェアコンポーネント(別名、ツール、コマンド、プロセス、実行可能ファイル、プログラム)をより複雑なコンポーネントにアセンブルし、それ自体がさらに複雑なコンポーネントにアセンブルされます。
  • 通常、スクリプトは実行可能になるため、名前で呼び出すことができます。呼び出されると、スクリプトを実行するための新しいサブプロセスが生成されます。ed export変数や関数のコピーは、値によってスクリプトに渡されます。これらの変数への変更は、親スクリプトに反映されませ
  • スクリプトは、呼び出し元スクリプトの一部であるかのようにロード(ソース)することもできます。これは、いくつかの他の言語が「インポート」または「インクルード」と呼ぶものに類似しています。ソースを取得すると、既存のプロセス内で実行されます。サブプロセスは生成されません。

関数を記述するタイミング...

  • 関数は、事実上プリロードされたシェルスクリプトです。機械的なディスクから読み取る必要がある場合のみ、別のスクリプトを呼び出すよりもパフォーマンスが少し向上します。今日のフラッシュドライブ、SSD、およびLinuxの未使用RAMの通常のキャッシングの急増により、その改善はほとんど測定できません。
  • 関数は、モジュール性、カプセル化、および再利用を実現するbashの主要な手段として機能します。スクリプトの明快さ、信頼性、保守性を向上させます。
  • 関数を呼び出すための構文規則は、実行可能ファイルを呼び出す場合と同じです。実行可能ファイルの代わりに、実行可能ファイルと同じ名前の関数が呼び出されます。
  • 関数は、それらが含まれているスクリプトに対してローカルです。
  • 関数をエクスポートできます(値によってコピーされます呼び出されたスクリプト内で使用できる)できます。したがって、関数は子プロセスにのみ伝播し、親には伝播しません。
  • 関数は再利用可能なコマンドを作成します。これらのコマンドは、多くの場合、ライブラリ(関数定義のみを含むスクリプト)にアセンブルされ、他のスクリプトから提供されます。

エイリアスを記述するタイミング...

ライブラリスクリプトなどのスクリプト内では、関数の名前が変更されても下位互換性が必要な場合など、関数のエイリアスが必要になることがあります。これは、すべての引数を新しい関数に渡す古い名前の単純な関数を作成することで実現できます...

# A bash in-script 'alias'
function oldFunction () { newFunction "$@"; }

9

私が信じていないもう1つのことがあります。関数は呼び出しプロセスのコンテキストで実行されますが、スクリプトは新しいシェルをフォークします。

これはパフォーマンスにとって重要になる可能性がfork()ありexec()ます。関数は高速ではありません。通常の状況では、違いはささいなことですが、メモリ不足でページスラッシングのあるシステムをデバッグしている場合、大きな違いが生じる可能性があります。

また、現在のシェル環境を変更する場合は、関数を使用する必要があります。たとえば、関数$PATHは現在のシェルのコマンドルックアップを変更できますが、スクリプトはのfork / execコピーで動作するため、変更できません$PATH


この子への関数の伝播はどのように機能しますか?
HappyFace

1
@HappyFace Bash export -fでは、関数を作成できますが、これの正確な内部動作はやや不明瞭です。これは、従来のBourneシェルに移植できないと思います。
トリプリー

7

スクリプトとエイリアス、およびスクリプトと関数は相互に排他的ではありません。スクリプトにエイリアスと関数を保存できます。

スクリプトは、永続化される単なるコードです。将来使用したい便利な関数とエイリアスはスクリプトに保存されます。ただし、スクリプトは多くの場合、複数の関数のコレクションです。

エイリアスはパラメーター化されていないため、非常に制限されています。通常、いくつかのデフォルトパラメータを定義します。

関数は、コードの別個のユニットであり、小さく、有用な部分に分離することができないコードの数行の明確に定義された概念。1つは直接再利用することも、他の機能で再利用することもできます。


5

非常に高速にする必要がある場合は、エイリアスまたは関数にします。

好みのシェルの外で使用できるようにする必要がある場合は、スクリプトにします。1

引数を取る場合は、関数またはスクリプトにします。

特殊文字を含める必要がある場合は、エイリアスまたはスクリプトにします。2

sudoを使用する必要がある場合は、エイリアスまたはスクリプトにします。3

ログアウトおよびログインせずに簡単に変更したい場合は、スクリプトの方が簡単です。4

脚注

1または、エイリアスにして、それ~/.envを設定して設定しますがexport ENV="$HOME/.env"、移植性のある動作をするのは複雑です。

2関数名は識別子でなければならないため、文字で始まる必要があり、文字、数字、アンダースコアのみを含めることができます。たとえば、エイリアスがありalias +='pushd +1'ます。関数にすることはできません。

3そしてエイリアスを追加しalias sudo='sudo 'ます。同上他のコマンドのようなstracegdb最初の引数としてコマンドを取り、等。

4参照:fpath。もちろんsource ~/.bashrc、同様のこともできますが、多くの場合、他の副作用があります。


1
+bashでエイリアスを作成できるとは知りませんでした。興味深いことに、テスト後、bash +ではエイリアスを作成できますが、関数は作成できないことを発見しましたが、zshはその逆です- +エイリアスではなく関数になります。
ケビン

zsh書く必要がありますalias -- +='some command here'
ミケル

どういうわけか、エイリアシングに+は移植性がないと思います。エイリアス名に関するPOSIX仕様を
-jw013

3
sudo使用率をカバーするための賛成票。脚注4については、エイリアス~/.bash_aliasesを関数定義に保存する~/.bash_functionsので、簡単sourceに(副作用の危険なしに)再作成できます。
アンソニージョゲガン

3

いくつかのメモを追加するだけです:

  • sudoでは、システムスクリプトを編集する必要がある場合など、個別のスクリプトのみを使用できます。次に例を示します。
sudo v /etc/rc.conf  #where v runs vim in a new terminal window;
  • エイリアスまたは関数のみが同じ名前のシステムコマンドを置き換えることができます(スクリプトdirをPATHの最後に追加すると仮定します。これは、システムコマンドと同じ名前のスクリプトを誤ってまたは悪意を持って作成する場合の安全性のために推奨されます)。例えば:
alias ls='ls --color=auto'  #enable colored output;
  • エイリアスと関数は実行に必要なメモリと時間は少なくなりますが、ロードには時間がかかります(シェルはプロンプトを表示する前にそれらをすべて解釈する必要があるため)。新しいシェルプロセスを定期的に実行する場合は、これを考慮してください。例:
# pressing key to open new terminal
# waiting for a few seconds before shell prompt finally appears.

それ以外は、可能な限り最も単純な形式を使用できます。つまり、最初にエイリアス、次に機能、次にスクリプトを検討します。


5
エイリアスはでも使用できsudoます。しかし、最初に必要alias sudo='sudo 'です。
ミケル

スクリプトを実行するとfork + execの実行中に一時的に多くのメモリが消費されるのは事実ですが、現在のシェルインスタンスのメモリに多くのコードがロードされると、多くの場合、今後多くのメモリが消費され、多くの場合、かなりまれに使用されます。
トリプリー

2

私の経験則は次のとおりです。

  • エイリアス-1つのコマンド、パラメーターなし
  • 関数-1つのコマンドのいくつかのパラメーター
  • スクリプト-いくつかのコマンド、パラメーターなし

1

マルチユーザー(またはマルチsysamin)環境では、すべてが短い「exec something ....」ラッパーになったとしても、すべてにスクリプトを使用します。

確かに、エイリアスや関数よりも技術的に遅い/効率的ではありませんが、それはほとんど問題になりません-そして、パスにある限り、スクリプトは常に動作します。

あなたの機能は、cron、sudoやenvなどの環境が縮小または変更されたものから呼び出されるか、ユーザーが別のシェルを使用しているだけかもしれません。

パフォーマンスに敏感なものがある場合は、それを特別なケースとして処理するか、より良い方法として、より機能的なスクリプト言語で書き直すトリガーを検討してください。

他のスクリプトでのみ使用される機能について話している場合は、標準のシェルを定義し、にできる関数ライブラリスクリプトを記述することも検討できます。私は他のすべてのスクリプトを入手しました。

T


0

エイリアスを使用する可能性が最も高い状況の例。

これは古い投稿であることは知っていますが、エイリアスとスクリプトの組み合わせを使用する必要がほとんどあり、関数を使用しないことを選択した状況を指摘したいと思います。

次のことを行うスクリプトが~/.bin/呼び出されsetupています:1

  1. 特定のディレクトリに移動します。
  2. いくつかの変数を定義します。
  3. ディレクトリの状態に関するメッセージを出力します。2

ポイントは、実行しただけでsetup <project-name>は、これらの変数を定義せず、ディレクトリにまったくアクセスしなかったことです。私が最良であるとわかった解決策は、このスクリプトをPATH追加alias setup=". ~/.bin/setup"して追加すること~/.bashrcでした。

ノート:

  1. 私はこのタスクにスクリプトを使用しましたが、関数ではなく、それが特に長いからではなく、編集できるので、使用後に更新する場合は編集後にファイルを取得する必要がないためです。
  2. すべてのドットファイルをリロードするスクリプトを作成したときに、似たようなケースがありました。3
  1. スクリプトはで提供されています私のドットファイルがリポジトリの下で.bin/
  2. スクリプトについて:このスクリプトに、上級で定義したプロジェクトの名前である引数を指定します。その後、スクリプトは、特定のcsvファイルに従って適切なディレクトリに移動することを知っています。定義する変数は、そのディレクトリのmakefileから取得されます。その後ls -l、スクリプトが実行さgit statusれ、そこで何が起こっているのかが示されます。
  3. このスクリプトは、私のdotfilesリポジトリでも利用可能です.bin/

1
ええと、エイリアスとスクリプトの組み合わせではなく、単なる関数でなければなりません。(ところで、環境は「環境」ではなく「環境」と綴られています。)
ワイルドカード

タイプミスについてコメントしてくれてありがとう、次のコミットで修正します。スクリプトの代わりに関数を使用することに関しては、おそらくこの特定のタスクに関数を使用し、これらのエイリアスを削除します。ポイントは、スクリプトを時々編集する場合、スクリプトとエイリアスを使用するのは非常に簡単な場合があることです
ドロンBehar

0

スクリプトを記述するタイミング

シェル以外のツールからコマンドを実行する場合。

これにはvim(私にとって)が含まれます:スクリプトとして記述されたフィルターや他のプログラムを持っている:%!my-filterので、エディターからプログラムを通してファイルをフィルターするようなことをすることができます。

my-filter関数またはエイリアスである場合、それは不可能です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.