다변수 For 루프

다변수 For 루프

for루프에서 정수뿐만 아니라 여러 변수를 지정하는 방법이 있습니까 bash? 처리해야 하는 임의의 텍스트가 포함된 파일이 2개 있을 수 있습니다.

내 기능은 다음과 같아야 합니다.

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

어떤 아이디어가 있나요?

답변1

첫 번째,줄을 읽을 때 for를 사용하지 마세요, 단어 분할을 통해 행을 읽는 데에는 여러 가지 피할 수 없는 문제가 있기 때문입니다.

파일의 길이가 같다고 가정하거나 두 파일 중 더 짧은 파일을 읽을 때까지 반복하려는 경우 간단한 해결책이 있습니다.

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

false가 반환되는 경우와 기타 여러 가지 이유로 인해 read보다 일반적인 솔루션을 구성하는 것은 어렵습니다 . 이 예제에서는 스트림을 얼마든지 읽을 수 있으며 가장 짧거나 긴 입력 후에 반환할 수 있습니다.

#!/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:

readN따라서 가져오는지 여부 에 따라 -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.

답변2

완료되었습니다. 완료되었습니다. 두 번의 for와 두 번의 완료가 필요합니다.

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

물론, 파일 2의 각 단어는 한 번씩 처리됩니다.

대부분의 경우 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

답변3

while흥미로운 구문이 있습니다. 루프 앞에 여러 명령을 넣을 수 있으며 do ... while문제의 상황에서는 특정 요구 사항(가장 긴 파일의 끝까지 읽는지, 아니면 가장 짧은 파일의 끝까지 읽는지 여부)에 따라 이 기능을 절충해야 할 수 있습니다.

예를 들어, read || read간단히작동하지 않습니다(질문에서 묻는대로) 첫 번째 파일을 읽을 때 true두 번째 파일을 읽은 것은 다음과 같습니다.뛰어 넘다첫 번째 파일을 처음부터 끝까지 읽을 때까지...그런 다음 상태가 still 이므로 truewhile 루프가 계속되어 두 번째 파일을 처음부터 끝까지 읽습니다.

read && read가장 짧은 파일만 읽으려는 경우 파일은 동시에(동기적으로) 읽혀집니다. 그러나 두 파일을 모두 로 읽으려면 구문 요구 사항을 eof충족해야 합니다 . while's즉시 명령을 전달하십시오.앞으로루프는 do whilewhile 루프를 벗어나기 위해 0이 아닌 반환 코드를 생성합니다.

다음은 두 파일을 읽는 방법에 대한 예입니다.에브

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를 테스트하고 싶을 수도 있지만 특히 최종 참/거짓 조건에 대한 일반적인 아이디어가 있습니다.

관련 정보