私はbashスクリプトを作成し、最初にコンパイルせずに実行しました。それは完全に機能しました。アクセス許可があってもなくても動作しますが、Cプログラムに関しては、ソースコードをコンパイルする必要があります。どうして?
私はbashスクリプトを作成し、最初にコンパイルせずに実行しました。それは完全に機能しました。アクセス許可があってもなくても動作しますが、Cプログラムに関しては、ソースコードをコンパイルする必要があります。どうして?
回答:
つまり、シェルスクリプトはコンパイルされず、解釈されます。シェルはスクリプトを一度に1つのコマンドで解釈し、各コマンドの実行方法を毎回把握します。とにかく、他のプログラムの実行にほとんどの時間を費やしているので、これはシェルスクリプトにとって理にかなっています。
一方、Cプログラムは通常コンパイルされます。実行できるようになる前に、コンパイラーはプログラム全体をマシンコードに変換します。過去にはCインタープリター(Atari STのHiSoftのCインタープリターなど)がありましたが、非常に珍しいものでした。最近のCコンパイラは非常に高速です。TCCは非常に高速なので、それを使用して「Cスクリプト」を作成できます。#!/usr/bin/tcc -run
そのため、シェルスクリプトと同じように実行されるCプログラムを作成できます(ユーザーの観点から)。
一部の言語には一般的にインタープリターとコンパイラーの両方があります。BASICは思い浮かぶ一例です。
いわゆるシェルスクリプトコンパイラも見つけることができますが、私が見たものはラッパーを難読化しているだけです。スクリプトを実際に解釈するためにシェルを使用しています。mtraceurポイント適切なシェルスクリプトコンパイラは確かに非常に興味深いだけではなく、可能でしょうけれども。
これについての別の考え方は、シェルのスクリプト解釈機能は、コマンドライン処理機能の拡張であり、当然、解釈されたアプローチにつながると考えることです。一方、Cはスタンドアロンのバイナリを生成するように設計されています。これはコンパイルされたアプローチにつながります。通常コンパイルされる言語は、インタプリタ、または少なくともコマンドラインパーサ(REPL、read-eval-print loopsとして知られています。シェル自体がREPLです)も開発する傾向があります。
execve
、open
、close
、read
、write
、およびpipe
いくつかが点在システムコール、getenv
、setenv
非エクスポート変数のために(、および内部ハッシュマップ/配列操作)、等Bourneシェルおよび誘導体は、プログラミングではない言語でもあり、そのコードの再順序付け、等のような低レベルのコンパイラの調整から限り恩恵
次のプログラムを検討してください。
2 Mars Bars
2 Milks
1 Bread
1 Corn Flakes
でbash
あなたは1を見たときにパンを認識することができ、「経験豊富な買い物客」と呼ばれる複雑なプログラムを実行されているための方法、あなたはなど、牛乳のためにこの作品を探してさまよう、その後、火星バーを探して店の周りにさまよい、最終的にはそれらを見つけますそして、ショッピングの他のすべての複雑さ。bash
かなり複雑なプログラムです。
または、ショッピングリストをショッピングコンパイラに渡すこともできます。コンパイラはしばらく考えて、新しいリストを提供します。このリストは長いですが、より簡単な手順で構成されています。
... lots of instructions on how to get to the store, get a shopping cart etc.
move west one aisle.
move north two sections.
move hand to shelf three.
grab object.
move hand to shopping cart.
release object.
... and so on and so forth.
ご覧のとおり、コンパイラはすべてがショップ内のどこにあるかを正確に把握しているため、「物を探す」フェーズ全体は必要ありません。
これはそれ自体がプログラムであり、「経験豊富な買い物客」を実行する必要はありません。必要なのは、「基本的な人間のオペレーティングシステム」を持つ人間だけです。
コンピュータープログラムに戻る:bash
「経験豊富な買い物客」であり、スクリプトを実行して、何もコンパイルせずにそれを実行できます。Cコンパイラーは、実行するためにもはや支援を必要としないスタンドアロンプログラムを生成します。
インタプリタとコンパイラには、それぞれ長所と短所があります。
それはすべて、人間がコンピュータが理解する機械命令に変換されるときに読み書きできるプログラムの技術的な違いに起因します。各メソッドの異なる長所と短所が、一部の言語がコンパイラを必要とするように書かれている理由です、そしていくつかは解釈されるように書かれています。
(注:質問に対処するために、ここでは多くのことを簡略化しています。より深く理解するために、私の回答の下部にあるテクニカルノートでは、ここでいくつかの簡略化を詳しく説明/洗練しており、この回答に関するコメントにはいくつかの有用な説明と議論も..)
プログラミング言語には、基本的に2つの一般的なカテゴリがあります。
Cは最初のカテゴリにあります(C コンパイラはC 言語をコンピュータのマシンコードに変換します。マシンコードはファイルに保存され、そのマシンコードを実行すると、必要な処理が行われます)。
bashは2番目のカテゴリにあります(bash インタープリターはbash 言語を読み取り、bash インタープリターは必要な処理を実行します。つまり、「コンパイラーモジュール」自体はなく、インタープリターは解釈と実行を行いますが、コンパイラーは読み取りと翻訳を行います)。 。
これが何を意味するかは、すでにお気づきかもしれません。
Cでは、「解釈」ステップを1回実行し、プログラムを実行する必要があるときはいつでも、コンピューターにマシンコードを実行するように指示するだけです。コンピューターは、余分な「思考」を行う必要なく、直接実行することができます。
bashでは、プログラムを実行するたびに「解釈」ステップを実行する必要があります。コンピューターはbashインタープリターを実行しており、bashインタープリターは追加の「思考」を行って、毎回コマンドごとに実行する必要があることを理解します。 。
そのため、Cプログラムでは、準備(コンパイル手順)に必要なCPU、メモリ、時間が長くなりますが、実行にかかる時間と作業は少なくなります。bashプログラムは、準備に必要なCPU、メモリ、時間は少なくなりますが、実行するのにより多くの時間と作業が必要です。最近のコンピューターは非常に高速であるため、ほとんどの場合、これらの違いに気付かないでしょうが、違いはあります。その違いは、大きなプログラムや複雑なプログラム、または多くの小さなプログラムを実行する必要がある場合に加算されます。
また、Cプログラムはコンピューターのマシンコード(「母国語」)に変換されるため、プログラムを取得して別のコンピューターコード(たとえば、Intel 64ビットからIntel 32)で別のコンピューターにコピーすることはできません。 -bit、またはIntelからARMまたはMIPSなどへ)。あなたは、他の機械語のためにそれをコンパイルする時間を費やす必要が再び。ただし、bashプログラムは、bashインタープリターがインストールされている別のコンピューターに移動するだけで、問題なく実行できます。
Cのメーカーは、数十年前からハードウェア上でオペレーティングシステムやその他のプログラムを作成していたが、それは現代の標準ではかなり制限されていた。さまざまな理由から、プログラムをコンピューターのマシンコードに変換することが、当時の目標を達成するための最良の方法でした。さらに、彼らが書いたコードが効率的に実行されることが重要な種類の作業を行っていました。
そして、Bourneシェルとbashのメーカーは反対を望んでいました:彼らはすぐに実行できるプログラム/コマンドを書きたかったです-コマンドラインで、ターミナルで、あなたはただ1行、1つのコマンドを書き、それを持ちたいのです。実行します。また、シェルインタープリター/プログラムがインストールされている場所であればどこでも機能するように記述したスクリプトが必要でした。
つまり、bashにはコンパイラは必要ありませんが、Cにはコンパイラが必要です。これらの言語は実際のコンピュータアクションに異なる方法で変換され、言語の目的が異なるため、それらの異なる方法が選択されました。
実際には、C インタープリターまたはbash コンパイラーを作成できます。。それが可能であることを妨げるものは何もありません。それは、それらの言語が異なる目的のために作成されたというだけです。多くの場合、複雑なプログラミング言語用の優れたインタープリターやコンパイラーを作成するよりも、単にプログラムを別の言語で書き直す方が簡単です。特に、それらの言語に得意な特定のものがあり、そもそも特定の方法で設計されている場合。Cはコンパイルするように設計されているため、対話型シェルでは必要な便利な省略形が多くありませんが、データ/メモリの非常に具体的で低レベルの操作を表現したり、オペレーティングシステムとやり取りしたりするのに非常に適しています。は、効率的にコンパイルされたコードを記述したいときによく行うタスクです。一方、bashは他のプログラムの実行が非常に得意です。
より高度な詳細:実際には両方のタイプが混在するプログラミング言語があります(これらはソースコードを「ほとんどすべて」翻訳するため、ほとんどの解釈/「思考」を一度に実行でき、ほんの少ししか実行できません解釈/後の「思考」)。Java、Python、および他の多くの現代言語は、実際にはそのようなブレンドです。それらは、インタープリター型言語の移植性および/または迅速な開発の利点のいくつか、およびコンパイル済み言語の速度のいくつかを取得しようとします。そのようなアプローチを組み合わせるには多くの可能な方法があり、言語が異なればそれは異なります。このトピックを掘り下げたい場合は、「バイトコード」にコンパイルするプログラミング言語を読むことができます(これは、独自の「機械語」にコンパイルするようなものです)
実行ビットについて質問しました。実際、実行可能ビットは、そのファイルの実行が許可されていることをオペレーティングシステムに伝えるためだけにあります。実行権限なしでbashスクリプトが機能する唯一の理由は、実際にはbashシェル内からスクリプトを実行しているためだと思います。通常、オペレーティングシステムは、実行ビットが設定されていないファイルを実行するように要求されると、エラーを返します。しかし、bashのような一部のシェルでは、基本的にオペレーティングシステムが通常実行する手順をエミュレートすることで、エラーを確認し、とにかくファイルを実行します(ファイルの先頭にある「#!」行を調べて、ファイルを解釈するためにそのプログラムを実行します。デフォルトはそれ自体、または/bin/sh
「#!」行がない場合)。
コンパイラがシステムにすでにインストールされている場合もあれば、IDEに独自のコンパイラが付属している場合や、コンパイルが実行される場合もあります。これにより、コンパイルされた言語を非コンパイル言語と同じように使用できるようになりますが、技術的な違いはまだあります。
「コンパイルされた」言語は必ずしもマシンコードにコンパイルされるわけではなく、これをコンパイルする全体がそれ自体がトピックです。基本的に、この用語は広く使用されています。実際にはいくつかのことを指します。ある特定の意味では、「コンパイラ」は、ある言語(通常、人間が使用しやすい「高レベル」の言語)から別の言語(通常、コンピュータが使用しやすい「低レベル」の言語)へのトランスレータにすぎません-時には、実際にはそれほど頻繁ではありませんが、これはマシンコードです)。また、人々が「コンパイラ」と言うとき、彼らは実際に一緒に動作する複数のプログラムについて話している(典型的なCコンパイラの場合、それは実際には「プリプロセッサ」、コンパイラ自体、「アセンブラ」、および「リンカ")。
プログラミング/スクリプト言語は、コンパイルまたは解釈できます。
コンパイルされた実行可能ファイルは常に高速で、実行前に多くのエラーを検出できます。
解釈された言語は通常、記述が簡単で、コンパイルされた言語ほど厳密ではないため適応が容易であり、配布するのを容易にするコンパイルを必要としません。
英語があなたの母国語ではないことを想像してください(英語が母国語でない場合、それはあなたにとって非常に簡単かもしれません)。
これを読む方法は3つあります。
コンピュータには、ある種の「母国語」があります。これは、プロセッサが理解する命令と、オペレーティングシステム(Windows、Linux、OSXなど)が理解する命令の組み合わせです。この言語は人間には読めません。
Bashなどのスクリプト言語は、通常、カテゴリ1と2に分類されます。これらは一度に1行ずつ取得し、その行を翻訳して実行してから、次の行に進みます。MacとLinuxでは、Bash、Python、Perlなどのさまざまな言語用に、かなりの数の異なるインタープリターがデフォルトでインストールされています。Windowsでは、これらを自分でインストールする必要があります。
多くのスクリプト言語は少し前処理を行います-頻繁に実行されるか、そうでなければアプリケーションを遅くするコードのチャンクをコンパイルすることによって実行をスピードアップしようとします。あなたが耳にするかもしれないいくつかの用語には、時間先行(AOT)またはジャストインタイム(JIT)コンパイルが含まれます。
最後に、Cのようなコンパイル済み言語は、プログラムを実行する前にプログラム全体を翻訳します。これには、実行とは異なるマシンで変換を実行できるという利点があります。そのため、プログラムをユーザーに提供するときに、まだバグがある可能性がある場合でも、いくつかのタイプのエラーはすでにクリーンアップできます。これを翻訳者に渡した場合と同じようgarboola mizene resplunks
に、がどのように有効な英語のように見えるかについてお話ししますが、翻訳者は私がナンセンスな話をしていることを教えてくれます。コンパイルされたプログラムを実行する場合、インタプリタは必要ありません-すでにコンピュータの母国語です
ただし、コンパイルされた言語には1つの欠点があります。コンピューターには、ハードウェアとオペレーティングシステムの機能で構成された母国語があると述べました。まあ、Windowsでプログラムをコンパイルした場合、コンパイルされたプログラムが動作することは期待できません。 Mac。一部の言語は、Pidgin Englishのような中途半端な言語にコンパイルすることでこの問題を回避します。これにより、コンパイルされた言語の利点とわずかな速度の向上を得ることができますが、バンドルする必要があります。コード付きのインタープリター(またはすでにインストールされているものを使用)。
最後に、IDEはおそらくファイルをコンパイルしていて、コードを実行する前にエラーについて通知することができます。場合によっては、このエラーチェックはコンパイラが行うよりも詳細になることがあります。多くの場合、コンパイラーは必要な量だけをチェックして、適切なネイティブコードを生成できるようにします。IDEは多くの場合、いくつかの追加チェックを実行し、たとえば、変数を2回定義したかどうか、または使用していないものをインポートしたかどうかを通知します。
多くの人が解釈とコンパイルについて話していますが、一部の解釈言語は実際に実行前に中間バイトコードにコンパイルされるため、よく見るとこれは少し誤解を招く可能性があると思います。
結局、Cプログラムを実行可能形式にコンパイルする必要がある本当の理由は、Cソースファイルのコードを実行可能なものに変換するためにコンピューターが多くの作業を行う必要があるため、製品を保存するのに意味があるからです。これらすべてが実行可能ファイルで機能するため、プログラムを実行するたびに再度実行する必要はありません。
一方、シェルインタープリターは、シェルスクリプトを「機械操作」に変換するためにほとんど作業を行う必要はありません。基本的には、スクリプトを1行ずつ読み取り、空白で分割し、ファイルのリダイレクトとパイプラインを設定して、fork + execを実行するだけです。シェルスクリプトのテキスト入力を解析および処理するオーバーヘッドは、シェルスクリプトでプロセスを起動するのにかかる時間と比較して非常に小さいため、単に解釈するのではなく、中間スクリプト形式でシェルスクリプトをコンパイルするのはやり過ぎです。ソースコードを直接。