다음은 내가 달성하려는 동작의 예입니다.
행 목록이 있고 각 행에는 공백으로 구분된 값이 포함되어 있다고 가정해 보겠습니다.
lines='John Smith
James Johnson'
사용자가 묻는 프롬프트를 누를 때 이름이나 성을 루프백하고 싶기 때문에 IFS를 전체적으로 변경합니다.
oIFS=$IFS
IFS='
'
for line in $lines; do
IFS=$oIFS
read name surname <<< $line
read -p "Do you want to echo name? surname otherwise "
if [[ $REPLY == "y" ]]; then
echo $name
else
echo $surname
fi
done
이것은 효과가 있지만 이 접근 방식은 나에게 적합하지 않은 것 같습니다.
- IFS를 변경했지만 아마도 복원하는 것을 잊었을 것입니다.
- 루프가 반복될 때마다 IFS를 복원합니다.
while IFS=...
여기서는 다음과 같이 사용할 수 있다는 것을 알았습니다 .
while IFS='
' read line ; do
echo $line
read name surname <<< $line
read -p "Do you want to echo name? surname otherwise "
if [[ $REPLY == "y" ]]; then
echo $name
else
echo $surname
fi
done <<< "$lines"
read -p
그러나 지속적인 입력 스트림으로 인해 프롬프트가 손상되므로 이는 옵션이 아닙니다.
한 가지 해결책은 for
다음과 같이 하나의 명령문에만 IFS를 설정하는 것입니다.
IFS='
' for line in $lines; do
...
done
하지만 bash는 이것을 허용하지 않습니다.
답변1
mapfile
먼저 /를 사용하여 입력 라인을 배열로 읽을 수 있습니다 readarray
.
lines='John Smith
James Johnson'
mapfile -t lines <<< "$lines"
for line in "${lines[@]}"; do
read name surname <<< "$line"
echo "name: $name surname: $surname"
done
lines
출력이 명령에서 나온 경우에도 마찬가지로 mapfile -t lines < <(somecommand)
직접 사용할 수 있습니다. 프로세스 교체는 파이프와 약간 비슷하지만 서브쉘에서 실행되는 파이프 부분의 문제를 방지합니다. lines
마지막 줄 끝에 개행 문자가 누락되었지만 하나 <<<
를 추가했습니다. mapfile
누락되더라도 신경 쓰지 마세요. 하지만 끝에 개행 문자가 있으면 lines
추가 항목을 보관할 빈 배열 항목을 얻게 됩니다. 이 문제는 프로세스 교체를 사용하여 우회할 수 있습니다.
여기,
while IFS=... read line ; do
...
read -p "Do you want to echo name? surname otherwise "
done <<< "$lines"
둘 다 read
동일한 입력에서 읽지만 (테스트되지 않음) 다른 파일 설명자를 사용하여 루프로 리디렉션하여 이 문제를 해결할 수 있다고 생각합니다. 예:
while IFS=... read -u 3 line ; do
...
read -p "Do you want to echo name? surname otherwise "
done 3<<< "$lines"
아니면 그게 중요한지 모르겠습니다 read <&3
.read -u
답변2
조작하는 대신 실제 목록(배열)을 사용하십시오 IFS
.
#!/bin/bash
lines=( 'John Smith' 'James Johnson' )
for line in "${lines[@]}"; do
names=($line)
echo "$line"
read -p "Do you want to echo name? surname otherwise "
if [[ $REPLY == "y" ]]; then
echo "${names[0]}"
else
echo "${names[1]}"
fi
done
물론 이는 이름과 성만 있다고 가정합니다. 이는 실제 사람에게는 해당되지 않지만 데이터에는 해당될 수 있습니다. 어쨌든 원본 코드는 동일한 가정을 하고 있으므로 문제가 되지 않을 것 같습니다.
서브셸에서 루프를 실행하여 원하는 대로 이 작업을 수행할 수도 있으므로 변경 사항은 IFS
서브셸에만 영향을 미칩니다.
#!/bin/bash
lines='John Smith
James Johnson'
(
oIFS=$IFS
IFS=$'\n'
for line in $lines; do
echo "$line"
IFS=$oIFS
read name surname <<< "$line"
read -p "Do you want to echo name? surname otherwise "
if [[ $REPLY == "y" ]]; then
echo "$name"
else
echo "$surname"
fi
done
)
### The IFS hasn't been changed here outside the subshell.