個々のコマンド/組み込み範囲に対してカスタムIFS値を設定することが可能であることがわかります。個々の明細にカスタムIFS値を設定する方法はありますか?明らかにそうではありません。これは、次のようにすると、この操作を試みるとグローバルIFS値が影響を受けるためです。
#check environment IFS value, it is space-tab-newline
printf "%s" "$IFS" | od -bc
0000000 040 011 012
\t \n
0000003
#invoke built-in with custom IFS
IFS=$'\n' read -r -d '' -a arr <<< "$str"
#environment IFS value remains unchanged as seen below
printf "%s" "$IFS" | od -bc
0000000 040 011 012
\t \n
0000003
#now attempt to set IFS for a single statement
IFS=$'\n' a=($str)
#BUT environment IFS value is overwritten as seen below
printf "%s" "$IFS" | od -bc
0000000 012
\n
0000001
答え1
一部のシェル(含むbash
)では:
IFS=: command eval 'p=($PATH)'
(sh / POSIXエミュレーションではない場合はbash
省略できますcommand
。)しかし、これは引用符なしの変数を使用する場合にも必要であり、ほとんどset -f
のシェルにはローカルスコープはありません。
zshを使用すると、次のことができます。
(){ local IFS=:; p=($=PATH); }
$=PATH
これは基本的に行われない単語分割を強制することです(変数拡張にはワイルドカードもないため、shシミュレーションを除いて必要ありませんzsh
)。set -f
しかしzsh
、$path
バンドルまたは$PATH
区切り記号に分割:p=(${(s[:])PATH})
またはp=("${(s[:]@)PATH}")
空の要素を保持します。
(){...}
(またはfunction {...}
)と呼ばれる。匿名関数通常、ローカル範囲を設定するために使用されます。関数ローカルスコープをサポートする他のシェルについても同様のことができます。
e() { eval "$@"; }
e 'local IFS=:; p=($PATH)'
POSIX シェルで変数とオプションのローカル範囲を指定するには、次の関数を使用することもできます。https://github.com/stephane-chazelas/misc-scripts/blob/master/locvar.sh。その後、次のように使用できます。
. /path/to/locvar.sh
var=3,2,2
call eval 'locvar IFS; locopt -f; IFS=,; set -- $var; a=$1 b=$2 c=$3'
(ところで、$PATH
上記の分割は、zsh
IFSがフィールドセパレータではなくフィールドセパレータである他のシェルを除いては無効です。)
IFS=$'\n' a=($str)
a=1 b=2
.
メモvar=value cmd
:
存在する:
var=value cmd arg
シェルは/path/to/cmd
新しいプロセスで実行され、incmd
とarg
inargv[]
とvar=value
inを渡しますenvp[]
。これは実際には変数の代入ではなく、環境変数を渡す以上のものです。処刑された注文する。 BourneまたはKornシェルでもset -k
作成できますcmd var=value arg
。
今これは非です処刑された。 Bourneシェルでは、aloneと同様にinが最終的に設定されvar=value some-builtin
ます。これは、例えば(無駄な)動作が組み込みかどうかに応じて変化することを意味する。var
var=value
var=value echo foo
echo
POSIXおよび/またはksh
Bourneの動作は次のクラスでのみ発生するため、これを変更しました。特殊組み込み機能。eval
特殊内蔵型ですread
。いいえ。特別でない組み込みコマンドの場合は、組み込みコマンドの実行のみが設定され、var=value builtin
外部var
コマンドの実行と同様に動作します。
このcommand
コマンドは削除に使用できます。特別なその属性特殊組み込み機能。 POSIXが無視することは、組み込み関数の場合、eval
シェルが変数スタックを実装する必要があることを意味します(コマンドを指定したりスコープを指定しなくても)。なぜなら、次のことができるからです.
。local
typeset
a=0; a=1 command eval 'a=2 command eval echo \$a; echo $a'; echo $a
でも:
a=1 command eval myfunction
使用、設定、呼び出すことができる関数ですmyfunction
。$a
command eval
(AT&Tはまだそれを実装していません)(AT&Tはまだ実装していません)ksh
(仕様はほとんどに基づいています)しかし、今、これら2つを除くほとんどのシェルは実装しているので、これは実際に監督でした。他のシェルは異なる動作をします。たとえば、次のようになります。ksh
zsh
a=0; a=1 command eval a=2; echo "$a"
しかし。これをサポートするシェルで使用することは、local
ローカルスコープを実装するより信頼性の高い方法です。
答え2
KernighanとPikeの「The Unixプログラミング環境」からの標準的な保存と復元:
#!/bin/sh
old_IFS=$IFS
IFS="something_new"
some_program_or_builtin
IFS=${old_IFS}
答え3
質問の一部は次のとおりです。
IFS=$'\n' a=($str)
左から右に評価される 2 つの個別のグローバル変数割り当てとして解釈されます。
IFS=$'\n'; a=($str)
または
IFS=$'\n'
a=($str)
これは、グローバルが変更される理由と、IFS
トークンが新しい値を持つ配列要素に分割される理由を説明します。$str
IFS
IFS
次のように変更効果を制限するためにサブシェルを使用できます。
str="value 0:value 1"
a=( old values )
( # Following code runs in a subshell
IFS=":"
a=($str)
printf 'Subshell IFS: %q\n' "${IFS}"
echo "Subshell: a[0]='${a[0]}' a[1]='${a[1]}'"
)
printf 'Parent IFS: %q\n' "${IFS}"
echo "Parent: a[0]='${a[0]}' a[1]='${a[1]}'"
a
しかし、すぐに修正がサブシェルに限定されていることがわかります。
Subshell IFS: :
Subshell: a[0]='value 0' a[1]='value 1'
Parent IFS: $' \t\n'
Parent: a[0]='old' a[1]='values'
次に、次のソリューションを使用してIFSを保存/復元できます。この以前の回答local IFS
@mswを使用するか、関数の内部を使用してみてください。提案に従ってください@helpermethodへ。しかし、すぐにあらゆる種類の問題に直面するでしょう。特に、スクリプト呼び出しの誤った動作に強力でなければならないライブラリの作成者であれば、そうです。
- 最初に設定されていない場合は
IFS
どうなりますか? set -u
(別名)を使って実行するとset -o nounset
どうなりますか?- 読み取り専用に設定すると
IFS
どうなりますかdeclare -r IFS
? trap
再帰および/または非同期実行(ハンドラなど)を処理するために保存/復元メカニズムが必要な場合はどうすればよいですか。
IFSを保存/復元しないでください。代わりに一時修正に固執してください。
変数の変更を単一のコマンド、組み込み、または関数呼び出しに制限するには
IFS="value" command
。複数の変数を特定の文字に分割して読み取るには(
:
以下の例のように)、次のようにします。IFS=":" read -r var1 var2 <<< "$str"
配列を読むには
array_var=( $str )
:IFS=":" read -r -a array_var <<< "$str"
変数変更の効果をサブシェルに制限します。
コンマで区切られた配列要素を出力するには、次のようにします。
(IFS=","; echo "${array[*]}")
文字列としてキャプチャするには:
csv="$(IFS=","; echo "${array[*]}")"
答え4
このコマンドの場合:
IFS=$'\n' a=($str)
別の回避策があります。最初の割り当て(IFS=$'\n'
)に実行するコマンド(関数)を指定します。
$ split(){ a=( $str ); }
$ IFS=$'\n' split
これにより、分割が呼び出される環境にIFSが配置されますが、現在の環境には残りません。
これは常に危険なevalの使用を防ぎます。