スクリプト内のコマンドの出力を配列に読み込む必要があります。コマンドは、例えば:
ps aux | grep | grep | x
そしてそれはこのように行ごとに出力を与えます:
10
20
30
コマンド出力から配列に値を読み取る必要があります。配列のサイズが3未満の場合は、いくつかの作業を行います。
スクリプト内のコマンドの出力を配列に読み込む必要があります。コマンドは、例えば:
ps aux | grep | grep | x
そしてそれはこのように行ごとに出力を与えます:
10
20
30
コマンド出力から配列に値を読み取る必要があります。配列のサイズが3未満の場合は、いくつかの作業を行います。
回答:
コマンドの出力は、(かなり頻繁にある)、スペースなどグロブ文字が含まれている場合、他の答えが壊れます*
、?
、[...]
。
要素ごとに1行の配列でコマンドの出力を取得するには、基本的に3つの方法があります。
Bash≥4を使用するとmapfile
、最も効率的です。
mapfile -t my_array < <( my_command )
それ以外の場合、出力を読み取るループ(低速ですが安全):
my_array=()
while IFS= read -r line; do
my_array+=( "$line" )
done < <( my_command )
Charles Duffyのコメント(ありがとう!)で示唆されているように、次のコードは、番号2のループメソッドよりもパフォーマンスが優れている可能性があります。
IFS=$'\n' read -r -d '' -a my_array < <( my_command && printf '\0' )
このフォームを正確に使用するようにしてください。つまり、次のものを用意してください。
IFS=$'\n'
同じ行にread
声明:これが唯一の環境変数を設定しますIFS
のためのread
唯一のステートメントを。そのため、スクリプトの残りの部分にはまったく影響しません。この変数の目的はread
、EOL文字でストリームを中断するよう指示すること\n
です。-r
: これは重要。バックスラッシュをエスケープシーケンスとして解釈しないように指示read
します。-d ''
:-d
オプションとその引数の間のスペースに注意してください''
。ここにスペースを残さ''
ないと、Bashがステートメントを解析する際の引用削除ステップでスペースが消えてしまうため、スペースは表示されません。これはread
、nilバイトで読み取りを停止するように指示します。一部の人々はそれを-d $'\0'
と書きますが、それは本当に必要ではありません。-d ''
優れている。-a my_array
ストリームの読み取り中read
に配列を設定するように指示しmy_array
ます。printf '\0'
ステートメントを使用する必要があるため、が戻ります。それはあなたがいない場合(あなただけのリターンコード取得します実際には大したことではありませんあなたが使用していない場合は大丈夫ですが、念頭に置いていることが、ちょうど熊-これはあなたがとにかくいけないが)。それはよりクリーンで、より意味的に正しいです。これは何も出力しないとは異なることに注意してください。nullバイトを出力します。そこから読み取りを停止するために必要です(オプションを覚えていますか?)。 my_command
read
0
1
set -e
printf ''
printf '\0'
read
-d ''
可能であれば、つまり、コードがBash≥4で実行できることが確実な場合は、最初の方法を使用してください。そして、あなたはそれがあまりにも短いのを見ることができます。
を使用する場合read
、行が読み取られるときに何らかの処理を実行する場合、ループ(メソッド2)がメソッド3よりも優れている可能性があります。ループに直接アクセスできます($line
上記の例の変数を介して)。また、すでに読んだ行にアクセスできます(${my_array[@]}
例で示した例の配列を介して)。
mapfile
は、各行を読み取るときにコールバックを評価する方法を提供することに注意してください。実際には、N本の行を読み取るごとにこのコールバックのみを呼び出すように指示することもできます。help mapfile
オプション-C
と-c
その中を見てください。(これについての私の意見は、それは少し不格好ですが、単純なことしかできない場合に時々使用できます-これが最初に実装された理由さえ本当に理解していません!)
ここで、次の方法を説明します。
my_array=( $( my_command) )
スペースがあると壊れます:
$ # I'm using this command to test:
$ echo "one two"; echo "three four"
one two
three four
$ # Now I'm going to use the broken method:
$ my_array=( $( echo "one two"; echo "three four" ) )
$ declare -p my_array
declare -a my_array='([0]="one" [1]="two" [2]="three" [3]="four")'
$ # As you can see, the fields are not the lines
$
$ # Now look at the correct method:
$ mapfile -t my_array < <(echo "one two"; echo "three four")
$ declare -p my_array
declare -a my_array='([0]="one two" [1]="three four")'
$ # Good!
次に、を使用IFS=$'\n'
してそれを修正することを勧める人もいます:
$ IFS=$'\n'
$ my_array=( $(echo "one two"; echo "three four") )
$ declare -p my_array
declare -a my_array='([0]="one two" [1]="three four")'
$ # It works!
しかし、今度はglobsで別のコマンドを使用してみましょう:
$ echo "* one two"; echo "[three four]"
* one two
[three four]
$ IFS=$'\n'
$ my_array=( $(echo "* one two"; echo "[three four]") )
$ declare -p my_array
declare -a my_array='([0]="* one two" [1]="t")'
$ # What?
それの私はと呼ばれるファイルがあるのでt
、現在のディレクトリにし...そして、このファイル名はで一致したグロブ [three four]
何人かの人々が使用することをお勧めします。この時点で... set -f
無効グロブへ:しかし、それを見て:あなたは変更する必要がありますIFS
し、使用set -f
修正できるようにするには壊れたテクニック(そして、あなたはそれを本当に修正さえしていません)!そうするとき、私たちは本当にシェルと戦っており、シェルを操作していません。
$ mapfile -t my_array < <( echo "* one two"; echo "[three four]")
$ declare -p my_array
declare -a my_array='([0]="* one two" [1]="[three four]")'
ここでは、シェルで作業しています!
mapfile
以前に聞いたことがありません、それはまさに私が何年も欠けていたものです。の最近のバージョンにbash
は素晴らしい新機能がたくさんあると思います。ドキュメントを読んで素敵なチートシートを書き留めるのに数日費やすだけです。
< <(command)
をシェルスクリプトで使用するには、shebang行を次のようにする必要があります#!/bin/bash
-として実行すると#!/bin/sh
、bashは構文エラーで終了します。
bash my_script.sh
はshコマンドではなくbashコマンドで実行する必要もありますsh my_script.sh
sh
なりdash
ません(もちろん、位置パラメータ$@
配列)。
IFS=$'\n' read -r -d '' -a my_array < <(my_command && printf '\0')
、bash 3.xでも正しく機能することと、失敗した終了ステータスをからmy_command
に渡すことを検討してくださいread
。
使用できます
my_array=( $(<command>) )
コマンドの出力を<command>
配列に格納しmy_array
ます。
その配列の長さにアクセスするには、
my_array_length=${#my_array[@]}
これで長さがに保存されmy_array_length
ます。
VAR="$(<command>)"
その後、my_array=("$VAR")
またはmy_array+=("$VAR")
ファイルとディレクトリ名(現在のフォルダーの下)を配列に入れて、その項目を数えると想像してください。スクリプトは次のようになります。
my_array=( `ls` )
my_array_length=${#my_array[@]}
echo $my_array_length
または、次のスクリプトを追加して、この配列を反復処理できます。
for element in "${my_array[@]}"
do
echo "${element}"
done
これはコアコンセプトであり、入力は以前に無害化されていると見なされていることに注意してください。つまり、余分な文字の削除、空の文字列の処理などです(これはこのスレッドのトピックではありません)。