「eval」と「source / dev / stdin」の違いは何ですか?


17

以下の選択肢の間...

  1. eval

    comd="ls"
    eval "$comd"
  2. source /dev/stdin

    printf "ls" | source /dev/stdin
  3. source /dev/stdin( ){ }

    ( printf "ls" ) | source /dev/stdin
    { printf "ls"; } | source /dev/stdin

    (で実行printfするとき{ }、サブシェルを使用しないこと以外の利点はありますか?)

    • それらの違いは何ですか?

    • どちらが好ましいですか?

    • コマンドを実行する好ましい方法はどれですか?()または{}


1
どちらのアプローチもお勧めしません。ユーザーが送信した任意のコードを実行する必要があると思う、実際に何をしようとしてますか?
chepner

2
また、質問を読むまで、彼らは任意のユーザー入力を(現状のまま)実行していました。しかし、あなたは彼らがそうなると予測しているかもしれません。
ctrl-alt-delor

回答:


17
  • 方法の違いは何ですか?

からbash manpage

eval [arg ...]
              The  args  are read and concatenated together into a single com
              mand.  This command is then read and executed by the shell,  and
              its  exit status is returned as the value of eval.  If there are
              no args, or only null arguments, eval returns 0.

source filename [arguments]
              Read and execute commands from filename  in  the  current  shell
              environment  and return the exit status of the last command exe
              cuted from filename.  If filename does not contain a slash, file
              names  in  PATH  are used to find the directory containing file
              name.  The file searched for in PATH  need  not  be  executable.
              When  bash  is  not  in  posix  mode,  the  current directory is
              searched if no file is found in PATH.  If the sourcepath  option
              to  the  shopt  builtin  command  is turned off, the PATH is not
              searched.  If any arguments are supplied, they become the  posi
              tional  parameters  when  filename  is  executed.  Otherwise the
              positional parameters are unchanged.  The return status  is  the
              status  of  the  last  command exited within the script (0 if no
              commands are executed), and false if filename is  not  found  or
              cannot be read.

2つの方法に違いはありません。

eval注が1つだけあります。すべての引数を連結し、単一のコマンドとして実行されます。sourceファイルの内容を読み取り、実行します。eval引数ではなくコマンドのみを構築できますstdin。そのため、次のようにすることはできません。

printf "ls" | eval
  • どちらがより好ましいですか?

例では同じ結果が得られますが、目的evalと目的sourceは異なります。source通常、他のスクリプト用のライブラリを提供するためにeval使用されますが、コマンドの評価にのみ使用されます。評価evalされた文字列がクリーンであるという保証はないため、可能な限り使用しないでください。subshell代わりにいくつかの健全性チェックを行う必要があります。

  • ()または{}でいくつかのコマンドを実行する場合、どちらがより望ましいですか?

中括弧内でシーケンスコマンドを実行すると{ }、すべてのコマンドはサブシェルではなく現在のシェルで実行されます(括弧内で実行する場合です(bash リファレンスを参照)。

を使用subshell ( )するとより多くのリソースが使用されますが、現在の環境は影響を受けません。を使用{ }すると、現在のシェルですべてのコマンドが実行されるため、環境が影響を受けます。目的に応じて、いずれかを選択できます。


2
あなたは質問を誤解したと思います。もちろん、あなたが交換することはできませんevalsource。質問は次のとおりだと思います:とeval "$cmd"同等echo "$cmd" | source /dev/stdinです。私の現在の意見:はい。
ハウケレイジング14

3

主な違いは、2番目と3番目の形式がパイプを使用していることです。これにより、bashはサブシェルで「source」コマンドを実行します(lastpipeが設定されていない限り、bash 4.2+でのみ使用可能)。 :

printf "ls" | bash

その結果、コードで設定された環境変数はすべて失われるため、期待どおりに機能しません。

printf "abc=2" | source /dev/stdin

現在のシェルでコマンドを実行するには、プロセス置換を使用できます。

source <(printf "abc=2")

通常どおりセミコロンを使用して、括弧内にさらにコマンドを配置できます。

この方法でパイプを削除すると、「eval」と「source」の使用に違いはないと思います。特定のケースで使用するのがより簡単なものを好む必要があります。

  • 変数で実行するコマンドが既にある場合は、「eval」を使用します
  • ファイルにそれらがある場合、または外部コマンドから取得する場合は、「ソース」を使用します

0

すでに与えられた答えを補完するものとして:

source相当...

comd="ls"
eval "$comd"

...は...

source <(printf ls)

以下の場合にはls有意な差はありません。

しかし、現在の環境影響与えることを目的とするコマンドの場合(使用するときに通常意図するものsource)、このバリアントはそれを行います(最初のソリューションevalもそうです)一方で、2番目のアプローチはサブシェルの環境に影響しますコード行を実行した後に使用可能になります。

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