각 반복이 시작될 때 여러 변수를 읽고 루프에 대한 사용자 입력을 읽어야 하는 사용 사례가 있습니다.
가능한 해결책을 탐색하는 방법을 모르겠습니다.
- 할당을 위해 표준 입력 대신 다른 파일 핸들을 사용하십시오.
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
에서 나오도록 합니다.stderr
stdin
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
,b
Zsh가 더 잘할 거예요.
답변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