私たちが知っているように、パスにはすべてのコンポーネントに改行文字を含めることができます。
$PATH
それでは、環境変数に改行文字を含めることができると結論付けるべきですか?
$PATH
それでは、Bourne likeのように要素にどのように分割できますか?
IFS=':' ; set -f
for var in $PATH
do
echo "<$var>"
done
ただし、IFSを変更せずに実行できる場合は、より良いでしょう。
答え1
POSIX シェルには$IFS
フィールドがあります。区切り記号、区切り文字の代わりにこれら$PATH
の値は、空の文字列(現在のディレクトリを表す)の代わりに分割され/bin:/usr/bin:
ます。以下を行う必要があります。/bin
/usr/bin
/bin
/usr/bin
IFS=:; set -o noglob
for var in $PATH""; do
printf '<%s>\n' "$var"
done
グローバル設定の変更を防ぐために、明示的な分割演算子でシェルを使用できますzsh
。たとえば、次のようになります。
for var in "${(s/:/@)PATH}"; do
printf '<%s>\n' "$var"
done
この場合、配列はzsh
すでに$path
/にバインドされているため、$PATH
次のようになります。csh
tcsh
for var in "$path[@]"; do
printf '<%s>\n' "$var"
done
とにかく、そうです。理論的には、$PATH
すべての変数に改行文字を含めることができるように、改行文字はファイルパスの解析では特別ではありません。私は、識別可能な人が名前$PATH
に改行(またはワイルドカード)を含むディレクトリを置くか、改行を含むコマンド名を指定することを期待していません。$PATH
改行が含まれていないと仮定するスクリプトを誰かが利用できるシナリオも想像するのは難しいです。
答え2
はい、PATH
改行文字を含めることができます(古いUnixシステムでも同様です)。
シェルで文字列を分割する場合、唯一の移植可能な方法はを使用することです。ただし、ループを使用する代わりに、それを使用したり関数に渡したりIFS
できます。IFS=:; set -f; set -- $PATH
for
bash
文字列を「読む」こともできます。大量に:
xtra=$'some\nother\nplace\n\n'; PATH="$PATH:$xtra"
mapfile -td: path < <(printf %s "$PATH")
printf '<%s>\n' "${path[@]}"
しかし、配列を使用することは、環境変数に透過的に格納したり、外部コマンドに単一の引数として渡したりすることはできないため、通常は良い考えではありません。
にIFS
なります。終了\n
フィールドを区別する代わりに(ファイルを1行ずつ読み取るプログラムでファイルの終わりを空行として扱わないのと似ています)、これが期待される結果ではなく実際に分割できるようにしたい場合は、文字で終わる文字列の末尾に追加の空のフィールドを作成します。するにはIFS
、単語を分割したい変数の後に空の文字列を追加する必要があります。
(P=/bin:; IFS=:; printf '<%s>\n' $P"")
</bin>
<>
IFS
単語分割アルゴリズムは、空白文字が文字列の一部である場合、文字列の先頭の空白文字も無視します。追加フィールドを先行スペースとして使用するには、変数の前に空の文字列も含める必要があります。
(P=' foo : bar '; IFS=': '; set -f; set -- $P; printf '<%s>\n' "$@")
<foo>
<bar>
(P=' foo : bar '; IFS=': '; set -f; set -- ""$P""; printf '<%s>\n' "$@")
<>
<foo>
<bar>
<>