2016-05-25 4 views
2

コマンドの出力をパラメータとして取得し、出力行の配列を返すbash関数です。 loginctl list-sessionssplitコマンドを行の配列に出力する

function get_lines { 
    while read -r line; do 
     echo $line 
    done <<< $1 
} 

SESSIONS=`loginctl list-sessions` 
get_lines "$SESSIONS" 

実際の出力は次のようになります。

SESSION  UID USER    SEAT    
     c2  1000 asif    seat0   
     c7  1002 sadia   seat0   

しかし、whileループは一度だけ、単一の行ですべての印刷出力を実行します。どのように行の配列を取得し、それを返すことができますか?

答えて

1

この回答の価値は、OPコードの問題点を説明することにあります。
- カスタムシェル機能を必要とせずに、配列の要素に行単位で入力を直接読み込むために、Bash v4 +の組み込みmapfile(またはその有効なエイリアスreadarray)の使用を示しています。
- Bash v3.xでは、IFS=$'\n' read -r -d '' -a lines < <(...),を使用できますが、空の行は無視されることに注意してください。


あなたの主な問題は、$1引用符で囲まれていない(非二重引用符で囲まれた)の使用は、シェルが効果的に空白のすべての実行を正規化し、その内容にword-splittingを適用可能ということである - 改行を含む - 1つのスペースにそれぞれ、の入力ラインのwhileループへの単一の結果となります。

二次的に、$inputを引用符で囲まずに使用すると、このワード分割がechoの出力に再び適用されます。

最後に、$IFS、内部フィールドセパレータを空の文字列(IFS= read -r line経由)に設定せずにreadを使用することによって、各入力行から空白が切り取られます。言っ

、あなたは標準入力ではなく、引数取ってから直接読み取るためにあなたの機能を簡素化することができます使用

get_lines < <(loginctl list-sessions) 

process substitutionを使用して、次のようにあなたがして呼び出すことができます

function get_lines { 
    while IFS= read -r line; do 
     printf '%s\n' "$line" 
    done 
} 

をパイプラインも機能しますが、get_linesサブシェルで実行されます。つまり、に現在表示されている変数を設定することはできません。シェル:

loginctl list-sessions | get_lines 
2

あなたがreadarray使用し、GET_LINES機能を避けることができます:

readarray SESSIONS < <(loginctl --no-legend list-sessions) 

これは、配列の要素にマッピングされたコマンドの出力の各行を配列SESSIONSを作成します。

+0

++が、末尾をキャプチャしないように、あなたは' -t'を追加する必要があります

SESSIONS='loginctl list-sessions' mapfile -t myArray <<< "$SESSIONS" 

は、参考文献各入力ラインと共に、 'readarray'にはBash 4.xが必要です。 – mklement0

+0

素晴らしいですね。私は '<<(' part。)何をしますか? – 8thperson

関連する問題