Lispプログラムでは、シェルを起動し、ユーザーが指定したファイル名を含むコマンドを渡す必要がある場合があります。こうしたプログラムは、あらゆる有効なファイル名を扱える必要があります。しかし、シェルは特定の文字を特別なものとして扱うため、ファイル名にこれらの文字が含まれていると、シェルが誤動作してしまいます。これらの文字を処理するには、関数
shell-quote-argument を使用してください:
この関数は、実際の内容が argument である引数をシェル構文で表現した文字列を返します。戻り値をシェルコマンドに連結し、それをシェルに渡して実行させることで、確実に動作するはずです。
この関数が具体的にどのような動作をするかは、使用しているオペレーティングシステムによって異なります。この関数は、システムの標準シェルの構文で動作するように設計されています。特殊なシェルを使用している場合は、この関数を再定義する必要があります。セキュリティ上の考慮事項を参照してください。
;; This example shows the behavior on GNU and Unix systems. (shell-quote-argument "foo > bar") ⇒ "foo\\ \\>\\ bar" ;; This example shows the behavior on MS-DOS and MS-Windows. (shell-quote-argument "foo > bar") ⇒ "\"foo > bar\""
shell-quote-argument を使用してシェルコマンドを構築する例を以下に示します。
(concat "diff -u "
(shell-quote-argument oldfile)
" "
(shell-quote-argument newfile))
オプションの posix 引数が nil
以外の場合、システムのシェルに関わらず、argument は POSIX
シェルのクォート規則に従ってクォートされます。これは、リモートホスト上でシェルが動作する可能性があり、そこでは一般的に POSIX
シェルが必要となる場合に有用です。
(shell-quote-argument "foo > bar" (file-remote-p default-directory))
The following two functions are useful for combining a list of individual
command-line argument strings into a single string, and taking a string
apart into a list of individual command-line arguments. These functions are
mainly intended for converting user input in the minibuffer, a Lisp string,
into a list of string arguments to be passed to make-process, call-process or
start-process, or for converting such lists of
arguments into a single Lisp string to be presented in the minibuffer or
echo area. Note that if a shell is involved (e.g., if using call-process-shell-command), arguments should still be
protected by shell-quote-argument; combine-and-quote-strings is not
intended to protect special characters from shell evaluation.
この関数は、ダブルクォート、シングルクォート、およびバックスラッシュによる引用符を尊重して、stringを部分文字列に分割します。
(split-string-shell-command "ls /tmp/'foo bar'")
⇒ ("ls" "/tmp/foo bar")
この関数は、split-stringと同様に、正規表現separatorsに一致する箇所でstringを部分文字列に分割します(文字列の作成を参照)。さらに、部分文字列からクォートを除去します。その後、これらの部分文字列のリストを作成して返します。
separators が省略された場合や nil
の場合、デフォルトで "\\s-+"
となります。これは、空白文字構文を用いて1文字以上の文字にマッチする正規表現です(構文クラス表を参照)。
この関数は2種類のクォート方式をサポートしています。文字列全体をダブルクォートで囲む方法 "…" と、個々の文字をバックスラッシュエスケープ ‘\’
で囲む方法です。後者はLispの文字列でも使用されているため、この関数ではそれらにも対応しています。
この関数は、必要に応じて各文字列をクォートしながら、list-of-strings
を一つの文字列に連結します。また、各文字列の間に separator という文字列を挿入します。separator が省略されているか、あるいは nil
の場合は、デフォルトで " "
が使用されます。戻り値は、結果として得られた文字列です。
list-of-strings 内でクォートが必要な文字列とは、separator を部分文字列として含むものです。文字列をクォートするには、それをダブルクォート "…"
で囲みます。最も単純なケースとして、個別のコマンドライン引数からコマンドを cons
する場合、空白文字が埋め込まれているすべての引数がクォートされます。
Emacsを実行するシステムでは、実行時に送信されるコマンドとその引数の合計最大長に制限が設けられています。外部コマンドで処理する引数のリストが任意に長くなる可能性がある場合、この制限を超えるリスクがあり、その場合はコマンドの実行に失敗します。場合によっては、引数リストの後続のパーティションに対してコマンドを複数回実行することで、この問題を回避できます。コマンドを複数回実行しても問題がないことが分かっている場合は、この関数を使用して引数リストをあらかじめパーティション分割できます:
この関数は、arguments に続くパーティションのリスト(文字列のリスト)を返します。command は、arguments で実行するコマンド(shellp が nil でない場合を除く。後述)を指定する文字列または文字列のリストであり、そのコマンドの呼び出しごとに渡す必要がある引数も含まれます。これにより、command と返されたパーティションのいずれかを組み合わせて構成したコマンドを実行しても、コマンドとその引数の最大合計長に関するシステムの制限を超えることはありません。
オプション引数 shellp が nil
以外の場合、この関数は command の先頭に shell-file-name と shell-command-switch を暗黙的に含めます(非同期プロセスの作成
を参照)。また、その場合、この関数は分割計算において、引用符やスペース文字によって占有される追加の長さを考慮します。
process-environment(オペレーティングシステム環境を参照)がコマンドラインの長さ制限にカウントされるシステムでは、この関数はその点も考慮します。
以下の例では、コマンドラインの長さに人為的に小さい制限を設け、デモンストレーション用に固定の process-environment
を指定しています。戻り値において引数リストが2つのサブリストに分割されていることは、この仮想システムで cmd foo bar baz
を実行するとシステム制限を超え、結果として失敗することを意味します。呼び出し側のコードでは、2つの分割箇所それぞれで cmd を2回、つまり cmd foo bar と cmd baz の順に実行する必要があります。
(let ((system-type 'gnu/linux)
(command-line-max-length 20)
(process-environment '("BLAH=blah")))
(multiple-command-partition-arguments "cmd" '("foo" "bar" "baz")))
⇒ (("foo" "bar") ("baz"))
この関数は保守的なアプローチを採用しており、arguments の分割数を最小限に抑えようとはしません。そうするにはプラットフォーム固有の膨大な情報に加え、現時点では Lisp で利用できないエンコーディングに関する情報も必要となるためです。
この変数には、multiple-command-partition-arguments
で使用される、本システムにおけるコマンドとその引数の最大長(文字数単位)が格納されています。