「set」というプログラムが実行されないのはなぜですか?


10

次のような簡単なCプログラムを作成しました。

int main(int argc, char *argv[]) {

    if (argc != 5) {
       fputs("Not enough arguments!\n", stderr);
       exit(EXIT_FAILURE);
    }

そして、私は自分のPATHをetc / bash.bashrcで次のように変更しています:

PATH=.:$PATH

このプログラムをset.cとして保存し、コンパイルしています。

gcc -o set set.c

フォルダ内

~/Programming/so

しかし、電話すると

set 2 3

何も起こりません。表示されるテキストはありません。

呼び出す

./set 2 3

期待される結果を与える

以前にPATHに問題があったことはありません。

which set

を返します./set。したがって、PATHが正しいようです。何が起こっているのですか?


10
「。」を追加するのは比較的危険です。あなたのPATHに。ローカルディレクトリから何かを実行するときは./を使用するか、実行可能ファイルを〜/ bin /などのよく知られたディレクトリに移動することをお勧めします
TREE

7
またtest、基本的に同じ理由でテストプログラムを呼び出すこともお勧めしません。testシェルも内蔵されています。
Jonathan Leffler、2015年

@JonathanLefflerしかも、簡単なテストではプログラムの呼び出しはtest理にかなっているようです。もちろん、あなたがそれをあなたの中に入れるときまでに、あなたPATHは本当に別の名前を思い付くはずでした。そして、プログラムを自分の中に置くまではPATH./testとにかくそれを呼び出さなければなりません。そのためtest、1日の終わりまでに削除する予定の簡単なテストである限り、プログラムの名前を使用しても問題ありません。
kasperd

1
@kasperd:私が知る限り、クイックテストプログラムの従来の名前はfooです。
hmakholmがモニカに残った

名前を付けるとls、存在するかどうかを確認するたびに実行されます(ただし、質問で行ったようにパスを変更した場合のみ)。
ctrl-alt-delor 2015

回答:


24

代わりに使用してのwhichその、あなたはそれが最も必要とするときは動作しません、使用はtype、コマンドを入力したときに実行されるか決定するために:

$ which set
./set
$ type set
set is a shell builtin

シェルは常にを検索する前に組み込み関数を検索する$PATHため、ここでは設定$PATHは役に立ちません。

実行可能ファイルの名前を別の名前に変更することをおset勧めしますが、割り当てにプログラムの名前を付ける必要がある場合は、シェル関数を使用できます。

$ function set { ./set; }
$ type set
set is a function
set ()
{
    ./set
}

(これはでも機能しますbashが、他のシェルでkshは許可されない場合があります。よりポータブルなソリューションについては、mikeservの回答を参照してください。)

入力setすると、「set」という名前の関数が実行され、が実行され./setます。GNU bashは組み込み関数を探す前に関数を探し、を検索する前に組み込み関数を探します$PATH。詳細については、bashのmanページの「COMMAND EXECUTION」というセクションを参照してください。

また、上のドキュメントを参照してくださいbuiltinとのcommandhelp builtinhelp command


3
あなたはtype以上をお勧めしますwhichが、理由を説明しないでください。(理由わかりますが、推奨事項を必要とする人はそうしません。)
cjm 2015年

1
ここ@cjmは上の全体の論文だ理由はありませんどのunix.stackexchange.com/questions/85249/...
アンソニーGeoghegan

非常に有益です。単純なタスクを実行するこのように見える単純なコマンドについて、多くの論争があるとは思わないでしょう
Ganea Dan Andrei

4
@GaneaDanAndrei主に、のtype代わりに使用しwhich、プログラムに「セット」という名前を付けないでくださいfunction set { ./set; }。これは、おそらく避けるべき醜いハックであることを認識してください。
yellowantphil 2015年

11

setbashの組み込みです(おそらく他のほとんどのシェル)。つまり、bashは関数を探すときにパスも検索しません。

余談ですが、.セキュリティ上の理由からパスに追加しないよう強くお勧めします。たとえば、他のユーザーが実行可能ファイルを追加した後のcdことを想像してみてください。/tmp/tmp/cd


2
うん、それはプログラム「を提示しながら、専門外の見えない,,するために、私の先生の力私たちにその愚かな考えだ彼の等級あなたがダウンしてそれが行われていない場合。。
Ganeaダン・アンドレイ

1
優れた教師のためのブラウニーポイント:(
klimpergeist 2015年

4
cdはシェル組み込みなので、この例はと同じ理由で機能しませんset
EmilJeřábek2015年

15
を使用./fooしてプログラムを呼び出すの専門的です。これは.、$ PATHに入れてはならない理由を理解していることを示しています。あなたの先生は間違っている、そしてあなたは私がそう言ったと彼に言うかもしれない。
zwol 2015年

10

set単なるビルトインではなく、POSIXの特殊なビルトインです。そこ何かの前にコマンド検索で見つかったことが、規格に指定されているいくつかの組み込みコマンドがある- $PATH関数名が検索されません、検索されない、となどですほとんどの組み込みコマンドではない 特別なが、実際にされている必要であることをPOSIX標準でシェルが独自の組み込みプロシージャを実行する$PATH 前に見つかりました。これが真のでecho最も他人と(ただし、この点で表彰された標準は、過去に開いたグループのメーリングリストでの競合の問題となっているかどうか)が、ないsettrapbreakreturncontinue.:timesevalexitexportreadonlyunset、またはexec

これらはすべてシェルの予約名であり、コマンド検索の優先順位以外にも特別な属性があります。たとえば、標準に準拠したシェルでは、これらの名前を使用してシェル関数を定義することはできません。これは良いことです。移植可能なスクリプトを安全に作成できるようになります。これらは、経験豊富なスクリプト作成者が自分の環境で安全で信頼できる足場を確立できるベースラインコマンドです。この名前空間に侵入することはお勧めできません

ただし、侵入したい場合は、を使用して移植できますalias。シェル展開の順序により、この回避策が可能になります。aliasコマンドの読み取り中にが展開されるため、set定義内で名前を置き換えるものはすべて正しく展開されますが、おそらくこれらの名前のいずれかに展開すべきではありません。

だからあなたはできる:

alias set=./set

...これで問題なく動作します。


3

問題は、それsetがシェルの組み込みであり、最良の解決策は、実行可能プログラムに別の名前使用することです。

ちなみに、先週、同じ名前のシェルビルトインの代わりにシステムコマンド実行する方法について質問しました。受け入れた解決策は、次のコマンドを実行することenvです。

env set 2 3

この特定のケースでは、使用するコマンドが現在のディレクトリにあることがすでにわかっている場合、パスを入力して実行可能ファイルを直接実行することをお勧めします(.現在の作業ディレクトリを表すために使用)。

./set 2 3

上記のソリューションはどちらもシェルに依存しません。つまり、使用しているシェルに関係なく機能します。

ビルトインの使用などの提案commandはBashでは機能しません。これはシェル関数の実行を妨げるだけです。文書化されていませんが、使用commandするとシェルキーワードも抑制されることにも気付きました。ただし、などのシェル組み込みコマンドでは同じことは行われませんset。私が理解しているcommandように、zshなどの他のシェルで動作する可能性があります。

また、Bashビルトインでは、\setorや"set"or などのトリック'set'は機能しません。ただし、エイリアスやシェルキーワードの代わりに実行可能ファイルを実行するのに役立ちます。

注:この回答は当初、エリックの(承認された)回答に対するコメントとして始まりましたが、コメントに収まらないほど大きくなりました。PATHの使用を推奨し、PATHにtype追加.しないことを推奨するその他の回答は、適切なものです。

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