web-dev-qa-db-ja.com

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

この質問をするのに私がLinuxを使うのに10年近くかかりました。それはすべて試行錯誤とランダムな深夜のインターネットサーフィンでした。

しかし、これには10年は必要ありません。 Linuxを使い始めたばかりの場合は、エイリアスを付けるタイミング、スクリプトを記述するタイミング、関数を記述するタイミングを知りたいですか?

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

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

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

alias command="bash bashscriptname"

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

それをする正当な理由はありますか?一生懸命頑張っていますが、やりたいと思うような状況は本当に考えられません。そのため、違いが生じるEdgeケースがある場合は、以下に回答してください。

それは私がPATHに何かを入れてそれをchmod +xする場所だからです。これは、長年のLinuxの試行錯誤の後に生まれたもう1つのことです。

次のトピックに進みます。たとえば、ホームディレクトリの隠しフォルダ(.scripts/)を.bashrcPATH=$PATH:/home/username/.scripts/)に行を追加するだけでPATHに追加したので、そこで実行可能なものはすべて自動的にオートコンプリートされます。

私がする必要がある場合。

本当に必要ないんですけどね? Pythonのように、シェル以外の言語でのみ使用します。

シェルの場合は、まったく同じ.bashrc内に関数を記述できます。

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

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

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

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

それでは、初心者のLinuxユーザーに、いつエイリアスを設定し、いつスクリプトを記述し、いつ関数を記述するかについて教えてください。

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

372
ixtmixilix

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

# 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

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

246
Kevin

他の回答は、個人的な好みに基づいたいくつかの柔らかい一般的なガイドラインを提供しますが、スクリプト、関数、またはエイリアスの間で決定するときに考慮する必要がある多くの適切なfactsを無視します。

エイリアスと関数¹

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

スクリプト

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

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

応用

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

  • シェル以外の他のプログラムで使用できるようにする必要がありますか?使用する場合は、スクリプトにする必要があります。

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

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

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

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


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

²Unixシステムで実行中のすべてのプロセスにはenvironmentがあり、_variable=value_のペアで構成されています。これには、デフォルトロケールのLANGPATHは、実行可能な検索パスを指定します。

267
jw013

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

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

動作するを実行することを制限するものは何もありません。

39
phunehehe

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

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

シェルスクリプトを見て、ここ数年私はエイリアスの作成をやや止めました(エイリアスはすべて時間の経過とともに関数に成長する傾向があるため)、bash以外の環境からも利用できるようにする必要がある場合にのみスクリプトを実行します。

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

15
nohillside

エイリアスと関数に関するいくつかの追加のポイントは次のとおりです。

  • 同じ名前エイリアスと関数は共存できます
  • エイリアス名前空間が検索されますfirst(最初の例を参照)
  • エイリアスできないサブシェルまたは非インタラクティブ環境で設定(設定解除)する(2番目の例を参照)

例えば:

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

ご覧のとおり、エイリアスと関数には別々の名前空間があります。詳細はdeclare -A -p BASH_ALIASESdeclare -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エイリアスの場合にすでに広く使用されています。関数の宣言よりもそうすることの利点は、同じ名前の関数をたまたま宣言しているスクリプトをsourceing(または.を使用)するだけではエイリアスを上書きできないことです。

11
leden

スクリプトを作成するタイミング...

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

いつ関数を書くか...

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

エイリアスを書き込むタイミング...

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

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

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

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

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

9
Jan Steinman

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

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

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

A 関数はコードの個別の単位、数行のコードの明確に定義された概念であり、小さくて便利な部分に分割することはできません。直接または他の機能によって他のものが再利用できるもの。

7
user unknown

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

使用するシェル以外でも使用できる場合は、スクリプトにします。1

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

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

Sudoで動作する必要がある場合は、エイリアスまたはスクリプトにします。

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

脚注

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

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

 そして、エイリアスalias Sudo='Sudo 'を追加します。コマンドを最初の引数として取るstracegdbなどの他のコマンドも同様です。

4 fpathも参照してください。もちろんsource ~/.bashrcや同様のこともできますが、これには他の副作用がよくあります。

6
Mikel

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

  • 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.

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

3
corvinus

私の経験則は:

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

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

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

あなたの機能はcronから、Sudoやenvなどの削減または変更された環境から呼び出されたり、ユーザーが異なるシェルを使用している可能性があります。

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

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

T

1
tjb63

いつスクリプトを書くか

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

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

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

0
D. Ben Knoble

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

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

私は~/.bin/setupと呼ばれる次のスクリプトを持っています。1

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

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

ノート:

  1. 私はこのタスクにスクリプトを使用しましたが、関数ではなく、特に長いのではなく、スクリプトを編集できるため、使用後に更新する場合は編集後にファイルを読み込む必要がないためです。
  2. すべてのdotfilesをリロードするスクリプトを作成したときに、同様のケースが発生しました。
  1. スクリプト.bin/の下にある my dotfiles repository で使用できます。
  2. スクリプトについて:私はこのスクリプトに、私が詳細に定義したプロジェクトの名前である引数を与えます。その後、スクリプトは特定のcsvファイルに従って正しいディレクトリに移動することを知っています。それが定義する変数は、そのディレクトリのmakefileから取得されます。その後、スクリプトはls -lおよびgit statusを実行して、そこで何が起こっているかを示します。
  3. そのスクリプトは、.bin/の下の私のdotfilesリポジトリでも利用できます。
0
Doron Behar