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 이므로 true
while 루프가 계속되어 두 번째 파일을 처음부터 끝까지 읽습니다.
read && read
가장 짧은 파일만 읽으려는 경우 파일은 동시에(동기적으로) 읽혀집니다. 그러나 두 파일을 모두 로 읽으려면 구문 요구 사항을 eof
충족해야 합니다 . while's
즉시 명령을 전달하십시오.앞으로루프는 do while
while 루프를 벗어나기 위해 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를 테스트하고 싶을 수도 있지만 특히 최종 참/거짓 조건에 대한 일반적인 아이디어가 있습니다.