多変数forループ


12

forループ内に複数の変数(整数だけでなく)を指定する方法はありますbashか?作業する必要がある任意のテキストを含む2つのファイルがある場合があります。

機能的に必要なのは次のようなものです:

for i in $(cat file1) and j in $(cat file2); do command $i $j; done

何か案は?

回答:


11

まず、for行を読み取らないください。単語分割による行の読み取りには避けられない問題がいくつかあります。

ファイルの長さが等しいと仮定するか、2つのファイルのうち短い方が読み取られるまでループするだけの場合は、簡単な解決策が可能です。

while read -r x && read -r y <&3; do
    ...
done <file1 3<file2

いつreadfalseが返されるか、その他のいくつかの理由により、より一般的なソリューションをまとめることは困難です。この例では、任意の数のストリームを読み取り、最短または最長の入力の後に戻ることができます。

#!/usr/bin/env bash

# Open the given files and assign the resulting FDs to arrName.
# openFDs arrname file1 [file2 ...]
openFDs() {
    local x y i arr=$1

    [[ -v $arr ]] || return 1
    shift

    for x; do
        { exec {y}<"$x"; } 2>/dev/null || return 1
        printf -v "${arr}[i++]" %d "$y"
    done
}

# closeFDs FD1 [FD2 ...]
closeFDs() {
    local x
    for x; do
        exec {x}<&-
    done
}

# Read one line from each of the given FDs and assign the output to arrName.
# If the first argument is -l, returns false only when all FDs reach EOF.
# readN [ -l ] arrName FD1 [FD2 ...]
readN() {
    if [[ $1 == -l ]]; then
        local longest
        shift
    else
        local longest=
    fi

    local i x y status arr=$1
    [[ -v $arr ]] || return 1
    shift

    for x; do
        if IFS= read -ru "$x" "${arr}[i]" || { unset -v "${arr}[i]"; [[ ${longest+_} ]] && return 1; }; then
            status=0
        fi
        ((i++))
    done
    return ${status:-1}
}

# readLines file1 [file2 ...]
readLines() {
    local -a fds lines
    trap 'closeFDs "${fds[@]}"' RETURN
    openFDs fds "$@" || return 1

    while readN -l lines "${fds[@]}"; do
        printf '%-1s ' "${lines[@]}"
        echo
    done
}

{
    readLines /dev/fd/{3..6} || { echo 'error occured' >&2; exit 1; }
} <<<$'a\nb\nc\nd' 3<&0 <<<$'1\n2\n3\n4\n5' 4<&0 <<<$'x\ny\nz' 5<&0 <<<$'7\n8\n9\n10\n11\n12' 6<&0

# vim: set fenc=utf-8 ff=unix ts=4 sts=4 sw=4 ft=sh nowrap et:

したがって、readNgets かどうかに応じて-l、出力は

a 1 x 7
b 2 y 8
c 3 z 9
d 4 10
5 11
12

または

a 1 x 7
b 2 y 8
c 3 z 9

すべてを複数の配列に保存せずにループで複数のストリームを読み取る必要があることは、それほど一般的ではありません。配列を読みたいだけなら、を見てくださいmapfile


||私にはうまくいきません。file1 、次に file2を処理しますが、ファイルの同期を維持し、最初のeofでwhileループ&&を終了します
-GNU

テストする暇がありませんでした-はい、おそらく反復ごとに両方の要素が必要です。||「リスト」演算子は、ほとんどの言語のように短絡されます。確かにこれは何千回も前に答えられました
...-ormaaj

ポイントは、以前に何かが言及された頻度ではありません。むしろ、回答で現在表示しているコードが機能しないということです。あなたの「おそらく両方の要素が欲しい」に基づいて、まだテストしていないようです。
Peter.O

@ Peter.O私は承知しています。修正されました。
-ormaaj

2

完了; 完了-2つのforsと2つのdonesが必要です:

for i in $(< file1); do for j in $(< file2); do echo $i $j;done ; done

もちろん、file2はfile1の各単語に対して1回処理されます。

catの代わりに<を使用すると、ほとんどの場合、パフォーマンスが大幅に向上します。サブプロセスは含まれません。(最後の文が不明)。

非圧縮:

for i in $(< file1)
do
  for j in $(< file2)
  do
    echo $i $j
  done
done

単語ではなく、行を読み、空白を保持したくない場合は、whileとreadを使用します。

while read line; do while read second; do echo "${line}${second}"; done <file2 ; done <file1

2つのファイルを追加し、それらをネストしない場合:

cat file1 file2 | while read line; do echo "${line}"; done

2つのファイルを圧縮する場合は、貼り付けを使用します。

paste file1 file2

1
関与するサブプロセスはないと言います。()はサブシェルではありませんか?私は懸命になりたくありませんが、私は今何が起こっているのか分かりません。たとえば、スクリプトがあり、たとえばcdで現在のシェルを汚染したくない場合は、()内で実行することを知っています。また、実行中(sleep 4)&の後にpsが続くと、プロセスがまだ実行中であることがわかります。詳しく説明してもらえますか。
シルバーロッカー

まあ-申し訳ありませんが、私はここで基礎なしに非常に演技しています。私はそう聞いたと思ったが、多分それは<と比較されるだけかもしれないcat。そして、私はそれをテストする方法と、それが意味的に重要になる時期がわかりません。パイプが呼び出された場合、サブプロセスの変数はメインプロセスにバブルアップしませんが、ここには変数がありません。誰かがそれを明確にすることができるまで、私は批判的な文章を打ちます。
ユーザー不明

0

whileinteresitng構文があります。do ... whileループの前に複数のコマンドを置くことができます。問題のケースでは、次の特定の要件に応じて、この機能を調整する必要があります。

たとえば、最初のファイルの読み取りがの場合、最初のファイルが最初から最後まで読み取られるまでスキップされるため、(質問の要件に応じて)read || read単に機能しません。isの場合、whileループは継続し、最初から最後まで2番目のファイルを読み取ります。 truetrue

read && read最短のファイルだけを読み取りたい場合は、ファイルを同時に(同期的に)読み取ります。ただし、両方のファイルをからに読み取りたい場合はeofwhile's構文要件を操作する必要があります。コマンドによってすぐ前にdo whileループはwhileループから抜け出すために、非ゼロの戻りコードを生成します。

両方のファイルをeofに読み込む方法の例を次に示します

while IFS= read -r line3 <&3 || ((eof3=1))
      IFS= read -r line4 <&4 || ((eof4=1))
      !((eof3 & eof4))
do
    echo "$line3, $line4"
done 3<file3 4<file4

(読み取りの前にeof3とeof4をテストすることもできますが、特に最終的なtrue / false条件では一般的な考え方があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.