BashスクリプトにおけるIFSの意味
1. 概要
このチュートリアルでは、特殊シェル変数内部フィールドセパレーター( IFS )について説明します。 最初に、 IFS 変数のデフォルト値について説明し、そのさまざまな使用例を理解します。 次に、 IFS でカスタム値を設定することにより、いくつかの実装について説明します。
2. IFS変数とそのデフォルト値
特別なシェル変数IFSは、文字列のシーケンスを分割するときにBashが単語の境界を認識する方法を決定します。 IFSのデフォルト値は、スペース、タブ、および改行で構成される3文字の文字列です:
$ echo "$IFS" | cat -et
^I$
$
ここでは、catコマンドの-eおよび-tオプションを使用して、IFS変数の特殊文字値を表示しました。
次に、スペースで区切られた文字列での単語の分割を示す例を実行してみましょう。
$ string="foo bar foobar"
$ for i in $string
> do
> echo "'$i' is the substring"
> done
'foo' is the substring
'bar' is the substring
'foobar' is the substring
文字列をループすると、スペースがIFS変数のデフォルト値の1つであるため、個々のサブ文字列を取得できます。
入力にタブ区切りの値が含まれている場合は、上記と同様の出力が表示されます。
for i in `echo -e "foo\tbar\tfoobar"`; do echo "'$i' is the substring"; done
スペースとタブに加えて、 IFS 変数は、デフォルト値としてa改行文字も保持します。 改行で区切られた入力に対するフィールド分割の効果を確認してみましょう。
$ string="foo
> bar
> foobar"
$ printf "%q\n" "$string"
$'foo\nbar\nfoobar'
$ for i in $string
> do
> echo "'$i' fetched from the string"
> done
'foo' fetched from the string
'bar' fetched from the string
'foobar' fetched from the string
ここで、改行で区切られたフィールドを複数行の入力から分割できます。
3. IFSでカスタム値を設定する
前のセクションでは、IFS変数のデフォルト値について学習しました。 さらに、IFS変数にカスタム値を設定することもできます。 これは、さまざまなフィールド区切りの文字列を処理するのに役立ちます。
例を使ってそれを行う方法を学びましょう:
$ string=foo:bar:foobar
$ old_ifs="$IFS"
$ IFS=":"
$ for i in $string
> do
> echo "'$i' is the splitted word"
> done
'foo' is the splitted word
'bar' is the splitted word
'foobar' is the splitted word
この例では、IFS変数の値を更新する前に、その値を別の変数old_ifsに格納しました。
したがって、後でこの変数を使用して、IFSを元の値にリセットできます。
IFS="$old_ifs"
IFS の設定を解除して、Bashの動作をデフォルトにリセットすることもできます。
$ echo "$IFS" | cat -et
^I$
$
$ string="foo bar foo:bar"
$ for i in $string; do echo "[$i] extracted"; done
[foo] extracted
[bar] extracted
[foo:bar] extracted
$ IFS=":" && echo "$IFS" | cat -et
:$
$ for i in $string; do echo "[$i] extracted"; done
[foo bar foo] extracted
[bar] extracted
$ unset IFS && echo "$IFS" | cat -et
$
$ for i in $string; do echo "[$i] extracted"; done
[foo] extracted
[bar] extracted
[foo:bar] extracted
IFS の設定を解除した後、BashはIFSがデフォルト値を保持しているかのように単語分割を処理したことに注意してください。
ただし、 IFS を空の文字列に設定すると、Bashは分割操作を実行しません。
$ IFS=""
$ for i in $string; do echo "[$i] extracted"; done
[foo bar foo:bar] extracted
3.1. デフォルトのIFSと カスタムIFS
IFS がデフォルトの空白文字値を保持している場合と、それが保持している場合の動作には微妙な違いがあります。 カスタム値を保持する場合。
IFS がデフォルト値に設定されている場合、先頭と末尾の空白文字は入力文字列から削除されます。 this とともに、連続する空白文字のシーケンスは単一の区切り文字として扱われます。 ただし、 IFS 変数にカスタム値が設定されている場合、この動作は観察されません。
例を使用して、デフォルトのIFSの動作を確認してみましょう。
string="foo bar foobar "
for i in $string
do
echo "[$i] extracted"
done
[foo] extracted
[bar] extracted
[foobar] extracted
ここで、入力文字列は、末尾のスペースと単語間の複数のスペースで構成されます。 ただし、Bashは末尾の空白文字を無視し、単語間の複数のスペースを単一の区切り文字として扱いました。
IFS 変数にカスタム値(コロン)を設定して、別の例を確認してみましょう。
$ string="foo:bar::foobar::"
$ IFS=":"
$ for i in $string
> do
> echo "[$i] extracted"
> done
[foo] extracted
[bar] extracted
[] extracted
[foobar] extracted
[] extracted
この場合、入力文字列の単語間の複数のコロンは、単一の区切り文字として扱われませんでした。
3.2. readコマンドの使用例
CSVの解析に関するarticleの例を使用して、readコマンドを使用したIFS変数の使用例を理解しましょう。
#! /bin/bash
while IFS="," read -r rec_column1 rec_column2 rec_column3 rec_column4
do
echo "Displaying Record-$rec_column1"
echo "Quantity: $rec_column2"
echo "Price: $rec_column3"
echo "Value: $rec_column4"
echo ""
done < <(tail -n +2 input.csv)
特に、whileループでIFSを“、” に設定して、input.csvの各行をトークンに分割しています。 その結果、 read コマンドを使用して、コンマ区切りのフィールド値をBash変数に解析できます。
3.3. IFSおよび位置パラメータ
特別なコマンドライン引数$@および$*は、Bashスクリプトまたは関数に渡される引数(位置パラメーター)のリストを保持します。
サンプルスクリプトを作成しましょう:
#!/bin/bash
echo " Input Parameters using \$@ : $@"
echo " Input Parameters using \$* : $*"
それでは、いくつかの位置パラメータを使用してスクリプトを実行してみましょう。
$ ./inputs.sh arg1 arg2 arg3
Input Parameters using $@ : arg1 arg2 arg3
Input Parameters using $* : arg1 arg2 arg3
ご覧のとおり、 $@と$* はどちらも、同様の方法でスクリプトへの入力引数を保持しています。 次に、スクリプトを更新して、IFS変数をカスタム値に設定します。
#!/bin/bash
IFS='|'
echo " Input Parameters using \$@ : $@"
echo " Input Parameters using \$* : $*"
実行出力を観察してみましょう。
$ ./inputs.sh arg1 arg2 arg3
Input Parameters using $@ : arg1 arg2 arg3
Input Parameters using $* : arg1|arg2|arg3
ここでの違いは、入力引数間の結合です。 $ IFS は、 $ *を使用する場合、位置パラメーターのセパレーターとして機能します。パラメーターは $ 1c $ 2 などに展開されます。ここで、 c は、IFSの最初の文字セットです。
4. 結論
このチュートリアルでは、Bashが単語の境界を認識して分割を実行する方法を学びました。
最初に、 IFS 変数のデフォルト値について説明し、そのさまざまな使用例を理解しました。 次に、 IFS にカスタム値を設定して、いくつかのケーススタディを実装しました。