この質問に対する答えはすべて、何らかの形で間違っています。
間違った答え#1
IFS=', ' read -r -a array <<< "$string"
1:これはの誤用です$IFS
。値$IFS
変数がされていないとした単一の可変長むしろそれは次のように取得された文字列の区切り、セットの単一文字各フィールドの文字列の区切り、read
入力ラインから離脱により終了することができる任意のセット内の文字(この例では、コンマまたはスペース)。
実際、世の中の本当のステッカーにとって、の完全な意味$IFS
は少し複雑です。bashマニュアルから:
シェルはIFSの各文字を区切り文字として扱い、これらの文字をフィールドターミネーターとして使用して、他の展開の結果を単語に分割します。IFSが設定されていない場合、またはその値がデフォルトの<space> <tab> <newline>である場合、以前の展開の結果の最初と最後の<space>、<tab>、および<newline>のシーケンスは無視され、先頭または末尾にないIFS文字のシーケンスは単語を区切るのに役立ちます。場合はIFSがデフォルト以外の値を持っているし、空白文字のシーケンス<スペース>、<タブ>、および<空白文字がIFS(IFS空白文字)の値にある限り、単語の最初と最後では無視されます。内の任意の文字IFSされていないIFS任意の隣接するとともに、空白をIFS空白文字は、フィールドを区切ります。IFSの空白文字のシーケンスも区切り文字として扱われます。IFSの値がnullの場合、単語分割は発生しません。
基本的に、デフォルト以外のnull以外の値の$IFS
場合、フィールドは(1)すべてが「IFS空白文字」のセットからの1つ以上の文字のシーケンス(つまり、<space>、<tab>と<newline>( "newline"は改行(LF)を意味します)はどこにも存在します$IFS
)の、または(2)に存在する非 "IFS空白文字"$IFS
周囲の「IFS空白文字」の入力行。
OPについては、前の段落で説明した2番目の分離モードが入力文字列に必要なものである可能性がありますが、最初に説明した最初の分離モードがまったく正しくないことは確かです。たとえば、彼の入力文字列がどうなったとしたら'Los Angeles, United States, North America'
?
IFS=', ' read -ra a <<<'Los Angeles, United States, North America'; declare -p a;
## declare -a a=([0]="Los" [1]="Angeles" [2]="United" [3]="States" [4]="North" [5]="America")
2:このソリューションを1文字の区切り文字(コンマ自体など、つまり後続のスペースや他の手荷物なし)で使用する場合でも、$string
変数の値にLFが含まれているread
と、最初のLFに遭遇したら処理を停止します。read
組み込みは、呼び出しごとに1行を処理します。この例ではhere-stringメカニズムを使用しているため、入力をステートメントにのみパイプまたはリダイレクトしている場合でもこれは当てはまり、未処理の入力は確実に失われます。を強化するコードread
read
組み込みは、それを含むコマンド構造内のデータフローをていません。
これが問題を引き起こす可能性は低いと主張することもできますが、それでも、可能であれば回避すべき微妙な危険です。これは、read
組み込み関数が実際に2つのレベルの入力分割を行うという事実によって引き起こされます。最初に行に、次にフィールドに分割されます。OPは1レベルの分割しか必要read
としないため、組み込みのこの使用法は適切ではなく、使用を避ける必要があります。
3:このソリューションの明らかではない潜在的な問題は、read
空のフィールドを保持している場合でも、空の場合は常に後続のフィールドを削除することです。ここにデモがあります:
string=', , a, , b, c, , , '; IFS=', ' read -ra a <<<"$string"; declare -p a;
## declare -a a=([0]="" [1]="" [2]="a" [3]="" [4]="b" [5]="c" [6]="" [7]="")
OPはこれを気にしないかもしれませんが、それでも知っておく価値のある制限です。ソリューションの堅牢性と一般性が低下します。
この問題はread
、後で説明するように、入力文字列に入力する直前にダミーの末尾の区切り文字を追加することで解決できます。
不正解#2
string="1:2:3:4:5"
set -f # avoid globbing (expansion of *).
array=(${string//:/ })
同様のアイデア:
t="one,two,three"
a=($(echo $t | tr ',' "\n"))
(注:欠落している括弧を、応答者が省略したように見えるコマンド置換の周りに追加しました。)
同様のアイデア:
string="1,2,3,4"
array=(`echo $string | sed 's/,/\n/g'`)
これらのソリューションは、配列割り当ての単語分割を利用して、文字列をフィールドに分割します。おかしなことに、同様にread
、一般的な単語分割でも$IFS
特殊変数が使用されますが、この場合は、デフォルト値の<space> <tab> <newline>に設定されていることを意味しています。に設定されているため、1つ以上のIFSのシーケンス文字(現在はすべて空白文字)はフィールド区切り文字と見なされます。
これは、によってコミットされる2レベルの分割の問題を解決します。read
ワード分割自体は1レベルの分割のみを構成するためです。ただし、以前と同様に、ここでの問題は、入力文字列の個々のフィールドに既に文字が含まれて$IFS
いる可能性があるため、単語分割操作中に不適切に分割されることです。これは、これらの回答者が提供するサンプル入力文字列には当てはまりません(どれほど便利か...)が、もちろん、このイディオムを使用したコードベースが次のリスクを冒すという事実は変わりません。この仮定が将来のある時点で違反された場合、爆破します。もう一度、私の反例を検討してください'Los Angeles, United States, North America'
(または'Los Angeles:United States:North America'
)。
また、単語分割が正常に続いてファイル名の拡張(別名パス名展開別名、行われている場合、文字を含む潜在的に破損した単語があろうグロブ)*
、?
または[
続いて]
(及び場合、extglob
設定されている、括弧フラグメントにより前?
、*
、+
、@
、または!
)それらをファイルシステムオブジェクトと照合し、それに応じて単語(「グロブ」)を拡張します。これら3人の回答者の1人目は、set -f
事前にしてグロビングを無効にする抑えています。技術的にこれは機能します(ただし、おそらく追加する必要があります)set +f
その後、それに依存する可能性のある後続のコードでグロビングを再度有効にします)。ただし、ローカルコードで基本的な文字列から配列への解析操作をハッキングするために、グローバルシェル設定を変更する必要はありません。
この回答の別の問題は、すべての空のフィールドが失われることです。これは、アプリケーションに応じて、問題となる場合とされない場合があります。
注:このソリューションを使用する場合は、コマンド置換(シェルをフォークする)を呼び出してパイプラインを起動するよりも、${string//:/ }
「パターン置換」形式のパラメーター展開を使用することをお勧めします。パラメータの拡張は純粋にシェル内部の操作であるため、外部の実行可能ファイル(tr
またはsed
)を実行します。(また、tr
およびsed
ソリューションの場合、入力変数はコマンド置換内で二重引用符で囲む必要があります。そうしないと、単語分割がecho
コマンドで有効になり、フィールド値が混乱する可能性があります。また、$(...)
コマンド置換形式が古い形式よりも望ましいです`...`
コマンド置換のネストを簡略化し、テキストエディタによる構文の強調表示を改善するためです。
不正解#3
str="a, b, c, d" # assuming there is a space after ',' as in Q
arr=(${str//,/}) # delete all occurrences of ','
この答えは#2とほとんど同じです。違いは、回答者はフィールドが2つの文字で区切られていると想定していることです$IFS
。彼は、パターン置換拡張を使用して非IFS表現の文字を削除し、単語分割を使用して、残っているIFS表現の区切り文字のフィールドを分割することにより、このかなり具体的なケースを解決しました。
これは非常に一般的なソリューションではありません。さらに、ここではコンマは実際には「プライマリ」区切り文字であり、フィールドを分割するためにコンマを削除してスペース文字に依存することは単に間違っていると主張できます。もう一度、私の反例を考えてみましょう'Los Angeles, United States, North America'
。
また、ファイル名を拡張すると、拡張された単語が破損する可能性がありますが、これは、set -f
およびによる割り当てのグロビングを一時的に無効にすることで防ぐことができますset +f
。
また、空のフィールドはすべて失われますが、アプリケーションによっては問題となる場合とそうでない場合があります。
不正解#4
string='first line
second line
third line'
oldIFS="$IFS"
IFS='
'
IFS=${IFS:0:1} # this is useful to format your code with tabs
lines=( $string )
IFS="$oldIFS"
これは、単語分割を使用してジョブを実行するという点で#2と#3に似ていますが、コード$IFS
は入力文字列に存在する1文字のフィールド区切り文字のみを含むように明示的に設定しているだけです。これは、OPのコンマスペース区切り文字などの複数文字のフィールド区切り文字では機能しないことを繰り返します。しかし、この例で使用されているLFのような1文字の区切り文字の場合、実際には完全に近いものになります。以前の間違った回答で見たように、フィールドを途中で意図せずに分割することはできません。必要に応じて、分割のレベルは1つだけです。
1つの問題は、前述のようにファイル名の展開によって影響を受ける単語が破損することですが、重要なステートメントをset -f
とでラップすることでこれを解決できますset +f
。
別の潜在的な問題は、前に定義したようにLFが「IFS空白文字」として修飾されるため、#2および#3と同様に、すべての空のフィールドが失われることです。もちろん、デリミタが「IFS空白文字」以外の場合は問題になりません。アプリケーションによっては、問題にならない場合もありますが、ソリューションの一般性は損なわれます。
つまり、1文字の区切り文字があり、それが非「IFS空白文字」であるか、空のフィールドを気にしないで、重要なステートメントをset -f
and set +f
でラップすると、このソリューションは機能します。 、ただしそれ以外の場合。
(また、参考のために、bashの変数へのLFの割り当ては、$'...'
構文などを使用するとより簡単に実行できますIFS=$'\n';
。)
不正解#5
countries='Paris, France, Europe'
OIFS="$IFS"
IFS=', ' array=($countries)
IFS="$OIFS"
同様のアイデア:
IFS=', ' eval 'array=($string)'
このソリューションは、実質的に#1($IFS
カンマスペースに設定される)と#2-4(単語分割を使用して文字列をフィールドに分割する)の間のクロスです。このため、上記の間違った答えのすべてに影響するほとんどすべての問題に苦しんでいます。
また、2番目のバリアントに関してはeval
、その引数は単一引用符で囲まれた文字列リテラルであるため、呼び出しは完全に不要であるように見える可能性があり、静的に認識されます。しかしeval
、この方法で使用することには、実際には非常に明白でない利点があります。通常、変数の割り当てのみで構成される単純なコマンドを実行すると、実際のコマンドワードが後に続かないため、シェル環境で割り当てが有効になります。
IFS=', '; ## changes $IFS in the shell environment
これは、単純なコマンドに複数の変数割り当てが含まれる場合でも当てはまります。繰り返しになりますが、コマンドワードがない限り、すべての変数の割り当てがシェル環境に影響します。
IFS=', ' array=($countries); ## changes both $IFS and $array in the shell environment
ただし、変数の割り当てがコマンド名に付加されている場合(これを「プレフィックス割り当て」と呼びます)、シェル環境には影響せず、組み込みかどうかに関係なく、実行されたコマンドの環境にのみ影響します。または外部:
IFS=', ' :; ## : is a builtin command, the $IFS assignment does not outlive it
IFS=', ' env; ## env is an external command, the $IFS assignment does not outlive it
bashマニュアルからの関連引用:
コマンド名が表示されない場合、変数の割り当ては現在のシェル環境に影響します。それ以外の場合、変数は実行されたコマンドの環境に追加され、現在のシェル環境には影響しません。
変数割り当てのこの機能を利用して$IFS
一時的にのみ変更することができます。これにより$OIFS
、最初のバリアントで変数を使用して行われているような保存と復元の全体を回避できます。しかし、ここで直面する課題は、実行する必要があるコマンド自体が単なる変数の割り当てであるため、$IFS
割り当てを一時的にするためのコマンドワードが含まれないことです。あなたは自分で考えているかもしれませんが、なぜ、何もしないコマンドワードを次のようなステートメントに追加しないでください。: builtin
、$IFS
割り当てを一時的するために、ですか?これは、$array
割り当てを一時的にするため、機能しません。
IFS=', ' array=($countries) :; ## fails; new $array value never escapes the : command
ですから、私たちは事実上行き詰まりに陥っています。しかし、eval
そのコードを実行すると、通常の静的ソースコードのようにシェル環境で実行されるため$array
、eval
引数内で代入を実行して、シェル環境で有効にすることができます。$IFS
、そのプレフィックスの割り当て接頭辞eval
コマンドのコマンドよりも長く存続しませんeval
。これは、まさにこのソリューションの2番目のバリアントで使用されているトリックです。
IFS=', ' eval 'array=($string)'; ## $IFS does not outlive the eval command, but $array does
ご覧のように、これは実際にはかなり巧妙なトリックであり、(少なくとも割り当ての効果に関して)かなり明白でない方法で、必要なものを正確に実現します。の関与にもかかわらず、私は実際には一般的にこのトリックに反対していませんeval
。セキュリティの脅威から保護するために、引数文字列を一重引用符で囲むように注意してください。
しかし、繰り返しになりますが、「すべての世界で最悪の」問題の集合体のため、これは依然としてOPの要件に対する誤った答えです。
不正解#6
IFS=', '; array=(Paris, France, Europe)
IFS=' ';declare -a array=(Paris France Europe)
えっと…何?OPには、配列に解析する必要がある文字列変数があります。この「答え」は、配列リテラルに貼り付けられた入力文字列の逐語的な内容から始まります。それが一つの方法だと思います。
回答者は、 $IFS
変数がすべてのコンテキストですべてのbash解析に影響を与えるますが、これは正しくありません。bashマニュアルから:
IFS 拡張後の単語分割に使用され、read組み込みコマンドで行を単語に分割するために使用される内部フィールド区切り文字。デフォルト値は<space> <tab> <newline>です。
したがって、$IFS
特殊変数は実際には2つのコンテキストでのみ使用されます:(1)展開後に実行される単語分割(bashソースコードを解析するときではない)、および(2)read
組み込みによって入力行を単語に分割するため。
これをもっと明確にしてみましょう。解析と実行を区別するのは良いことだと思います。Bashは最初にソースコードを解析する必要があります。これは明らかに解析イベントであり、その後、コードを実行します。このとき、拡張機能が画面に入ります。拡張は実際には実行イベントです。さらに、$IFS
上で引用した変数の説明に問題があります。展開後に単語分割が実行されると言うのではなく、単語分割が実行されると言います時に拡大、または、おそらくより正確には、単語の分割があるの一部拡張プロセス。「単語分割」という語句は、この拡張ステップのみを指します。残念ながらドキュメントは「split」や「words」という単語を頻繁に投げているようですが、bashソースコードの解析を参照するために使用することはできません。次に、bashマニュアルのlinux.die.netバージョンからの関連する抜粋を示します。
展開は、単語に分割された後、コマンドラインで実行されます。実行される展開には、ブレース展開、チルダ展開、パラメータと変数展開、コマンド置換、算術展開、単語分割、パス名展開の 7種類があります。
展開の順序は次のとおりです。チルダ展開、パラメーターおよび変数展開、算術展開、およびコマンド置換(左から右に実行)。単語分割; およびパス名の展開。
あなたはGNUのバージョンを議論することができます展開セクションの最初の文で「words」ではなく「tokens」という単語を選択しているため、マニュアルののほうが少し優れてます。
展開は、トークンに分割された後、コマンドラインで実行されます。
重要な点は、$IFS
bashがソースコードを解析する方法を変更しないことです。bashソースコードの解析は、実際には非常に複雑なプロセスであり、コマンドシーケンス、コマンドリスト、パイプライン、パラメーター展開、算術置換、コマンド置換などのシェル文法のさまざまな要素の認識が含まれます。ほとんどの場合、bash解析プロセスは、変数割り当てなどのユーザーレベルのアクションでは変更できません(実際には、このルールにはいくつかの小さな例外があります。たとえば、さまざまなシェル設定を参照してください)compatxx
、オンザフライで解析動作の特定の側面を変更できます)。この複雑な解析プロセスから生じる上流の「単語」/「トークン」は、上記のドキュメントの抜粋で分解された「拡張」の一般的なプロセスに従って展開されます。言葉は単にそのプロセスの1つのステップです。単語分割は、前の拡張ステップから吐き出されたテキストにのみ影響します。ソースバイトストリームから解析されたリテラルテキストには影響しません。
不正解#7
string='first line
second line
third line'
while read -r line; do lines+=("$line"); done <<<"$string"
これは最良のソリューションの1つです。を再び使用することに注意してくださいread
。read
1つだけ必要なときに2つのレベルの分割を実行するため、これは不適切だと以前に言っていませんか ここでの秘訣は、read
呼び出しごとに1レベルの分割のみを効果的に行うように呼び出すことができるということです。これは、呼び出しごとに1つのフィールドのみを分割することにより、ループ内で繰り返し呼び出す必要があるというコストを必要とします。それは少し手技ですが、うまくいきます。
しかし、問題があります。まず、少なくとも1つのNAME引数をread
に指定すると、入力文字列から分割された各フィールドの先頭と末尾の空白は自動的に無視されます。これは$IFS
、この投稿で前述したように、がデフォルト値に設定されているかどうかに関係なく発生します。さて、OPは彼の特定のユースケースについてこれを気にしないかもしれません、そして実際、それは解析動作の望ましい機能かもしれません。しかし、文字列を解析してフィールドにしたいすべての人がこれを望んでいるわけではありません。ただし、解決策があります。のやや目立たない使用法read
は、ゼロのNAME引数を渡すことです。この場合、read
は、入力ストリームから取得した入力行全体をという名前の変数に格納します。$REPLY
おまけとして、ではありません値から先頭と末尾の空白を取り除きます。これは、read
私がシェルプログラミングのキャリアで頻繁に利用した非常に堅牢な使用法です。これが動作の違いのデモです。
string=$' a b \n c d \n e f '; ## input string
a=(); while read -r line; do a+=("$line"); done <<<"$string"; declare -p a;
## declare -a a=([0]="a b" [1]="c d" [2]="e f") ## read trimmed surrounding whitespace
a=(); while read -r; do a+=("$REPLY"); done <<<"$string"; declare -p a;
## declare -a a=([0]=" a b " [1]=" c d " [2]=" e f ") ## no trimming
このソリューションの2番目の問題は、OPのカンマスペースなどのカスタムフィールドセパレーターのケースに実際には対応しないことです。以前と同様に、複数文字のセパレータはサポートされていません。これは、このソリューションの残念な制限です。-d
オプションにセパレータを指定することにより、少なくともコンマで分割しようとすることができますが、何が起こるか見てください:
string='Paris, France, Europe';
a=(); while read -rd,; do a+=("$REPLY"); done <<<"$string"; declare -p a;
## declare -a a=([0]="Paris" [1]=" France")
予想外に、考慮されていない周囲の空白がフィールド値に取り込まれるため、後でトリミング操作によって修正する必要があります(これは、whileループで直接行うこともできます)。しかし、もう1つの明らかなエラーがあります。ヨーロッパがありません!それがどうなったのか?その答えはread
、最終フィールドで最終フィールドターミネータに遭遇することなく、ファイルの終わり(この場合は文字列の終わりと呼ぶことができます)にヒットした場合、失敗した戻りコードを返します。これにより、whileループが途中で中断し、最後のフィールドが失われます。
技術的には、この同じエラーが前の例にも影響を与えました。違いは、フィールド区切り文字がLFであると見なされたことです。これは、-d
オプションを指定しない場合のデフォルトであり、<<<
( "here-string")メカニズムは、それをフィードする直前に文字列にLFを自動的に追加しますコマンドへの入力。したがって、それらのケースでは、意図せずに追加のダミーターミネーターを入力に追加することにより、最終フィールドのドロップの問題を誤って解決しました。このソリューションを「ダミーターミネーター」ソリューションと呼びましょう。here-stringでインスタンス化するときに、自分で入力文字列に対して連結することにより、カスタム区切り文字にダミーターミネーターソリューションを手動で適用できます。
a=(); while read -rd,; do a+=("$REPLY"); done <<<"$string,"; declare -p a;
declare -a a=([0]="Paris" [1]=" France" [2]=" Europe")
そこで、問題は解決しました。別の解決策は、(1)read
が失敗を返し、(2)$REPLY
が空の場合、つまりread
ファイルの終わりに到達する前に文字を読み取ることができなかった場合にのみ、whileループを解除することです。デモ:
a=(); while read -rd,|| [[ -n "$REPLY" ]]; do a+=("$REPLY"); done <<<"$string"; declare -p a;
## declare -a a=([0]="Paris" [1]=" France" [2]=$' Europe\n')
このアプローチは、<<<
リダイレクト演算子によってhere-stringに自動的に追加される秘密のLFも明らかにします。もちろん、先ほど説明したように明示的なトリミング操作で個別に取り除くこともできますが、手動のダミーターミネーターのアプローチで直接解決できるので、そのまま使用できます。手動のダミーターミネーターソリューションは、これら2つの問題(ドロップされたファイナルフィールドの問題と追加されたLFの問題)の両方を一度に解決するという点で、実際には非常に便利です。
したがって、全体として、これは非常に強力なソリューションです。残りの弱点は、後で説明する複数文字の区切り文字のサポートがないことだけです。
不正解#8
string='first line
second line
third line'
readarray -t lines <<<"$string"
(これは実際には#7と同じ投稿からのものです。回答者は同じ投稿で2つのソリューションを提供しました。)
のreadarray
同義語である組み込みmapfile
は理想的です。これは、バイトストリームを解析して配列変数に一度に変換する組み込みコマンドです。ループ、条件、置換、その他をいじる必要はありません。また、入力文字列から空白をこっそり取り除きません。また、(-O
指定されていない場合)ターゲット配列に割り当てる前に、それを消去します。しかし、それはまだ完璧ではないので、「間違った答え」としてそれを批判します。
まず、これを邪魔にならないようにするためにread
、フィールド解析を実行するときの動作と同じようにreadarray
、後続のフィールドが空の場合はそれをドロップすることに注意してください。繰り返しますが、これはおそらくOPの問題ではありませんが、一部のユースケースでは問題になる可能性があります。すぐに戻ってきます。
次に、以前と同様に、複数文字の区切り文字はサポートされていません。この問題についても、すぐに修正します。
第3に、記述されたソリューションはOPの入力文字列を解析せず、実際には、そのままでは解析に使用できません。これについても少し詳しく説明します。
上記の理由により、私はこれをOPの質問に対する「間違った答え」であるとまだ考えています。以下に、私が正しい答えであると考えるものを示します。
正しい答え
オプションを指定するだけで#8を機能させる単純な試みを以下に示し-d
ます。
string='Paris, France, Europe';
readarray -td, a <<<"$string"; declare -p a;
## declare -a a=([0]="Paris" [1]=" France" [2]=$' Europe\n')
結果はread
、#7で説明したループソリューションの二重条件アプローチから得られた結果と同じであることがわかります。これは手動のダミーターミネータートリックでほぼ解決できます:
readarray -td, a <<<"$string,"; declare -p a;
## declare -a a=([0]="Paris" [1]=" France" [2]=" Europe" [3]=$'\n')
ここでの問題はreadarray
、<<<
リダイレクト演算子が入力文字列にLFを追加したため、後続のフィールドが保持されていたため、後続のフィールドが空ではなかった(そうでない場合は削除された)ことです。事後的に最終的な配列要素の設定を明示的に解除することで、これを処理できます。
readarray -td, a <<<"$string,"; unset 'a[-1]'; declare -p a;
## declare -a a=([0]="Paris" [1]=" France" [2]=" Europe")
残る2つの問題は、実際には関連していますが、(1)トリムする必要のある余分な空白、および(2)複数文字の区切り文字のサポートの欠如です。
もちろん、空白は後で削除できます(たとえば、Bash変数から空白を削除する方法を参照してください?)。しかし、複数文字の区切り文字をハッキングできれば、両方の問題を一度に解決できます。
残念ながら、複数文字の区切り文字を機能させる直接的な方法はありません。私が考えた最善の解決策は、入力文字列を前処理して、複数文字の区切り文字を、入力文字列の内容と衝突しないことが保証される単一文字の区切り文字に置き換えることです。この保証がある唯一の文字はNULバイトです。これは、bashでは(ちなみにzshではありません)、変数にNULバイトを含めることができないためです。この前処理ステップは、プロセス置換のインラインで実行できます。これはawkを使用してそれを行う方法です:
readarray -td '' a < <(awk '{ gsub(/, /,"\0"); print; }' <<<"$string, "); unset 'a[-1]';
declare -p a;
## declare -a a=([0]="Paris" [1]="France" [2]="Europe")
やっと!この解決策は、フィールドを途中で誤って分割したり、時期尚早に切り取ったり、空のフィールドをドロップしたり、ファイル名の展開でそれ自体が破損したり、先頭と末尾の空白を自動的に削除したり、最後に隠れたLFを残したりしません。ループを必要とせず、単一文字の区切り文字を処理しません。
トリミングソリューション
最後に、のあいまいな-C callback
オプションを使用して、独自のかなり複雑なトリミングソリューションをデモンストレーションしたいと思いましたreadarray
。残念ながら、私はStack Overflowの厳格な30,000文字の投稿制限に対して余裕がなくなったので、それを説明することはできません。読者の練習問題として残しておきます。
function mfcb { local val="$4"; "$1"; eval "$2[$3]=\$val;"; };
function val_ltrim { if [[ "$val" =~ ^[[:space:]]+ ]]; then val="${val:${#BASH_REMATCH[0]}}"; fi; };
function val_rtrim { if [[ "$val" =~ [[:space:]]+$ ]]; then val="${val:0:${#val}-${#BASH_REMATCH[0]}}"; fi; };
function val_trim { val_ltrim; val_rtrim; };
readarray -c1 -C 'mfcb val_trim a' -td, <<<"$string,"; unset 'a[-1]'; declare -p a;
## declare -a a=([0]="Paris" [1]="France" [2]="Europe")
,
(カンマスペース)の区切りについての質問であり、カンマなどの単一の文字についての質問ではないためです。あなたは後者のみに興味があるなら、答えはここに従うことが容易です:stackoverflow.com/questions/918886/...