읽기로 구동되는 while 루프에서 읽기를 힌트로 사용하시겠습니까?

읽기로 구동되는 while 루프에서 읽기를 힌트로 사용하시겠습니까?

각 반복이 시작될 때 여러 변수를 읽고 루프에 대한 사용자 입력을 읽어야 하는 사용 사례가 있습니다.

가능한 해결책을 탐색하는 방법을 모르겠습니다.

  1. 할당을 위해 표준 입력 대신 다른 파일 핸들을 사용하십시오.
  2. for대신 루프를 사용하세요 ... 루프 안에 여러 변수를 할당하는 ... | while read ...방법을 모르겠습니다for

    echo -e "1 2 3\n4 5 6" |\
    while read a b c; 
    do 
      echo "$a -> $b -> $c";
      echo "Enter a number:";
      read d ;
      echo "This number is $d" ; 
    done
    

답변1

read내가 올바르게 하고 있다면 기본적으로 값 목록을 반복한 다음 루프 내부에서 다른 값을 반복하고 싶을 것입니다 .

여기에는 몇 가지 옵션이 있습니다. 1과 2가 아마도 가장 현명할 것입니다.

1. 문자열을 사용하여 배열 시뮬레이션

2D 배열을 갖는 것은 좋지만 Bash에서는 불가능합니다. 값에 공백이 없는 경우 대략적인 해결 방법은 세 숫자의 각 집합을 문자열에 붙여넣은 다음 루프 내에서 문자열을 분할하는 것입니다.

for x in "1 2 3" "4 5 6"; do 
  read a b c <<< "$x"; 
  read -p "Enter a number: " d
  echo "$a - $b - $c - $d ";
done

물론 for x in 1:2:3 ...및 와 같은 다른 구분 기호를 사용할 수도 있습니다 IFS=: read a b c <<< "$x".


2. 파이프를 무료 표준 입력으로 리디렉션되는 다른 파이프로 교체하십시오.

또 다른 가능성은 다른 fd에서 읽고 read a b c해당 fd에 직접 입력하는 것입니다(표준 쉘에서 작동해야 함).

while read a b c <&3; do
    printf "Enter a number: "
    read d
    echo "$a - $b - $c - $d ";
done 3<<EOF
1 2 3
4 5 6
EOF

명령에서 데이터를 가져오려면 여기에서 프로세스 대체를 사용할 수도 있습니다. ( while read a b c <&3; ...done 3< <(echo $'1 2 3\n4 5 6')프로세스 대체는 bash/ksh/zsh의 기능입니다.)


3. stderr에서 사용자 입력 받기

또는 대신 예제와 같은 파이프를 사용하되 사용자 입력이 파이프 소스 대신 (fd 2) read에서 나오도록 합니다.stderrstdin

echo $'1 2 3\n4 5 6' |
while read a b c; do 
    read -u 2 -p "Enter a number: " d
    echo "$a - $b - $c - $d ";
done

읽기는 stderr약간 이상하지만 실제로는 대화형 세션에서 자주 작동합니다. ( /dev/tty실제로 리디렉션을 우회하려는 경우 명시적으로 열 수도 있습니다 . 이는 less데이터가 파이프로 연결되어 있어도 사용자의 입력을 얻는 데 사용되는 것과 유사합니다.)

stderr하지만 이와 같이 사용하면 모든 경우에 작동하지 않을 수 있으며 대신 외부 명령을 사용하는 경우 read최소한 해당 명령에 대한 여러 리디렉션을 추가해야 합니다.

또한보십시오내 변수가 하나의 "읽는 동안" 루프에서는 로컬이지만 겉보기에 유사한 다른 루프에서는 로컬이 아닌 이유는 무엇입니까?몇 가지 관련 질문이 있습니다 ... | while.


4. 필요에 따라 어레이의 일부를 슬라이스합니다.

일반 1D 배열의 슬라이스를 복사하여 2D 배열을 근사화할 수도 있다고 생각합니다.

data=(1 2 3 
      4 5 6)

n=3
for ((i=0; i < "${#data[@]}"; i += n)); do
    a=( "${data[@]:i:n}" )
    read -p "Enter a number: " d
    echo "${a[0]} - ${a[1]} - ${a[2]} - $d "
done

변수의 이름을 원할 경우 , etc ${a[0]}에 등을 할당 할 수도 있지만 a,bZsh가 더 잘할 거예요.

답변2

는 하나만 있으며 /dev/stdin사용 read되는 모든 위치에서 읽혀집니다(기본적으로).

해결책은 1( ) 대신 다른 파일 설명자를 사용하는 것입니다 /dev/stdin.

동등한 코드(bash)에서 게시한 내용까지[1](아래 표시) "실제" tty에서 읽으려면 (예를 들어)
추가하기만 하면 됩니다 .0</dev/tty

while read a b c
do    read -p "Enter a number: " d  0</dev/tty   # 0<&2 is also valid
      echo "$a -> $b -> $c and ++> $d"
done  <<<"$(echo -e '1 2 3\n4 5 6')"

실행 시:

$ ./script
Enter a number: 789
1 -> 2 -> 3 and ++> 789
Enter a number: 333
4 -> 5 -> 6 and ++> 333

또 다른 옵션은 사용하는 것입니다 0<&2(이상해 보일 수 있지만 작동합니다).

읽기 /dev/tty(또한 0<&2)는 스크립트의 표준 입력을 우회하므로 echo에서 값을 읽지 않습니다.

$ echo -e "33\n44" | ./script

기타 솔루션

필요한 것은 하나의 입력을 다른 fd(파일 설명자)로 리디렉션하는 것입니다.
ksh, bash 및 zsh에서 유효합니다.

while read -u 7 a b c
do    printf "Enter a number: "
      read d
      echo "$a -> $b -> $c and ++> $d"
done  7<<<"$(echo -e '1 2 3\n4 5 6')"

또는 exec를 사용하세요.

exec 7<<<"$(echo -e '1 2 3\n4 5 6')"

while read -u 7 a b c
do    printf "Enter a number: "      
      read d
      echo "$a -> $b -> $c and ++> $d"
done  

exec 7>&-

sh에서 작동하는 솔루션( <<<작동하지 않음):

exec 7<<-\_EOT_
1 2 3
4 5 6
_EOT_

while read a b c  <&7
do    printf "Enter a number: "      
      read d
      echo "$a -> $b -> $c and ++> $d"
done  

exec 7>&-

그러나 이것은 이해하기 더 쉬울 수 있습니다.

while read a b c  0<&7
do    printf "Enter a number: "      
      read d
      echo "$a -> $b -> $c and ++> $d"
done  7<<-\_EOT_
1 2 3
4 5 6
_EOT_

간단한 코드 1개

귀하의 코드는 다음과 같습니다

echo -e "1 2 3\n4 5 6" |\
while read a b c; 
do 
  echo "$a -> $b -> $c";
  echo "Enter a number: ";
  read d ;
  echo "This number is $d" ; 
done

단순화된 코드(Bash)는 다음과 같습니다.

while read a b c
do    #0</dev/tty
      read -p "Enter a number: " d ;
      echo "$a -> $b -> $c and ++> $d";
done  <<<"$(echo -e '1 2 3\n4 5 6')"

실행되면 다음이 인쇄됩니다.

$ ./script
1 -> 2 -> 3 and ++> 4 5 6

이는 var d가 동일한 이라는 것을 보여줍니다 /dev/stdin.

답변3

를 사용하려면 zsh다음과 같이 작성할 수 있습니다.

for a b c (
  1 2 3
  4 5 6
  'more complex' $'\n\n' '*** values ***'
) {
  read 'd?Enter a number: '
  do-something-with $a $b $c $d
}

2D 배열의 경우 ksh93셸도 참조하세요.

a=(
  (1 2 3)
  (4 5 6)
  ('more complex' $'\n\n' '*** values ***')
)
for i in "${!a[@]}"; do
  read 'd?Enter a number: '
  do-something-with "${a[i][0]}" "${a[i][1]}" "${a[i][2]}" "$d"
done

관련 정보