파일을 한 줄씩 읽고, 조건이 충족되면 다음 조건이 나올 때까지 계속 읽습니다. [닫기]

파일을 한 줄씩 읽고, 조건이 충족되면 다음 조건이 나올 때까지 계속 읽습니다. [닫기]

foo.txt 파일이 있습니다

test
qwe
asd
xca
asdfarrf
sxcad
asdfa
sdca
dac
dacqa
ea
sdcv
asgfa
sdcv
ewq
qwe
a
df
fa
vas
fg
fasdf
eqw
qwe
aefawasd
adfae
asdfwe
asdf
era
fbn
tsgnjd
nuydid
hyhnydf
gby
asfga
dsg
eqw
qwe
rtargt
raga
adfgasgaa
asgarhsdtj
shyjuysy
sdgh
jstht
ewq
sdtjstsa
sdghysdmks
aadfbgns,
asfhytewat
bafg
q4t
qwe
asfdg5ab
fgshtsadtyh
wafbvg
nasfga
ghafg
ewq
qwe
afghta
asg56ang
adfg643
5aasdfgr5
asdfg
fdagh5t
ewq

별도의 파일 qwe과 사이의 모든 줄을 인쇄하고 싶습니다. ewq이것이 내가 지금까지 가지고 있는 것입니다:

#!/bin/bash

filename="foo.txt"

#While loop to read line by line
while read -r line
do
    readLine=$line
    #If the line starts with ST then echo the line
    if [[ $readLine = qwe* ]] ; then
        echo "$readLine"
        read line
        readLine=$line
        if [[ $readLine = ewq* ]] ; then
            echo "$readLine"
        fi
    fi
done < "$filename"

답변1

특정 순서 없이 스크립트를 일부 변경해야 합니다.

  • 선행 및 후행 공백을 제거하지 않으려면 IFS=before를 사용하세요 .read
  • 어디에도 변화가 없기 때문에 $line변수가 필요하지 않습니다 readLine.
  • 루프 중간에 읽기를 사용하지 마십시오! ! .
  • 부울 변수를 사용하여 인쇄를 제어합니다.
  • 인쇄의 시작과 끝을 지정합니다.

이러한 변경 후 스크립트는 다음과 같습니다.

#!/bin/bash

filename="foo.txt"

#While loop to read line by line
while IFS= read -r line; do
    #If the line starts with ST then set var to yes.
    if [[ $line == qwe* ]] ; then
        printline="yes"
        # Just t make each line start very clear, remove in use.
        echo "----------------------->>"
    fi
    # If variable is yes, print the line.
    if [[ $printline == "yes" ]] ; then
        echo "$line"
    fi
    #If the line starts with ST then set var to no.
    if [[ $line == ewq* ]] ; then
        printline="no"
        # Just to make each line end very clear, remove in use.
        echo "----------------------------<<"
    fi
done < "$filename"

다음과 같이 요약할 수 있습니다.

#!/bin/bash
filename="foo.txt"
while IFS= read -r line; do
    [[ $line == qwe* ]]       && printline="yes"
    [[ $printline == "yes" ]] && echo "$line"
    [[ $line == ewq* ]]       && printline="no"
done < "$filename"

그러면 시작 줄과 끝 줄(포함)이 인쇄됩니다.
인쇄할 필요가 없으면 시작 및 종료 테스트를 바꿉니다.

#!/bin/bash
filename="foo.txt"
while IFS= read -r line; do
    [[ $line == ewq* ]]       && printline="no"
    [[ $printline == "yes" ]] && echo "$line"
    [[ $line == qwe* ]]       && printline="yes"
done < "$filename"

readarray그러나 배열 요소와 루프를 사용하는 것이 더 좋습니다(bash 버전 4.0 이상인 경우).

#!/bin/dash
filename="infile"

readarray -t lines < "$filename"


for line in "${lines[@]}"; do
    [[ $line == ewq* ]]       && printline="no"
    [[ $printline == "yes" ]] && echo "$line"
    [[ $line == qwe* ]]       && printline="yes"
done

이렇게 하면 read.


물론 sed처리하려는 행만 가져오기 위해 권장(주석에서, 감사합니다, @costas) 줄을 사용할 수 있습니다.

    #!/bin/bash
filename="foo.txt"

readarray -t lines <<< "$(sed -n '/^qwe.*/,/^ewq.*/p' "$filename")"

for line in "${lines[@]}"; do

     : # Do all your additional processing here, with a clean input.

done 

답변2

@Costas가 지적했듯이 작업에 적합한 도구는 다음과 같습니다 sed.

sed '/qwe/,/ewq/ w other.file' foo.txt

인쇄할 라인에 대한 추가 처리가 필요할 수 있습니다. 괜찮습니다. 이렇게 하세요.

sed -e '/qwe/,/ewq/{w other.file' -e 'other processing;}' foo.txt

(물론 "다른 처리"는 실제 sed명령이 아닙니다.) 위는 처리를 해야 할 경우 사용하는 패턴입니다.뒤쪽에라인을 인쇄합니다. 추가 처리를 수행한 다음 변경된 버전의 줄을 인쇄하려면(가능성이 더 높음) 다음을 사용할 수 있습니다.

sed -e '/qwe/,/ewq/{processing;w other.file' -e '}' foo.txt

(자체 매개변수에 넣어야 합니다 }. 그렇지 않으면 이름의 일부로 해석됩니다 other.file.)


귀하(OP)는 온라인에서 수행해야 하는 "추가 처리"가 무엇인지 명시하지 않았거나 더 구체적으로 설명할 수 있습니다. 그러나 처리가 무엇이든 확실히 거기에서 처리할 수 있습니다. 또는 이것이 너무 다루기 어려워지면 위의 코드를 거의 변경하지 않고 sed처리 할 수 있습니다.awk

awk '/qwe/,/ewq/ { print > "other.file" }' foo.txt

그런 다음 프로그래밍 언어의 모든 기능을 사용하여 awk명령문을 실행하기 전에 개별 줄을 처리 할 수 있습니다 print. 물론입니다 awk(그리고 sed) 그렇습니다디자인됨텍스트 처리의 경우 bash.

답변3

qwe(){ printf %s\\n "$1"; }
ewq(){ :; }
IFS=   ### prep  the  loop, only IFS= once
while  read -r  in
do     case $in in
       (qwe|ewq)
           set "$in"
       ;;
       ("$processing"?)
           "$process"
       esac
       "$1" "$in"
done

이것은 매우 느린 방법입니다. GNU grep와 일반infile:

IFS=
while grep  -xm1 qwe
do    while read  -r  in  &&
            [ ewq != "$in" ]
      do    printf %s\\n "$in"
            : some processing
      done
done <infile

...비효율적인 읽기의 절반 이상을 최적화합니다...

sed  -ne '/^qwe$/,/^ewq$/H;$!{/^qwe$/!d;}' \
      -e "x;s/'"'/&\\&&/g;s/\n/'"' '/g"    \
      -e "s/\(.*\) .e.*/p '\1/p" <input    |
sh    -c 'p(){  printf %s\\n "$@"
                for l do : process "$l"
                done
          }; . /dev/fd/0'

read이렇게 하면 출력을 두 번 인쇄해야 하지만 대부분 sh의 경우 비효율성을 피할 수 있습니다 . 한 번은 stdout에 대한 참조를 사용 sh하고 한 번은 stdout에 대한 참조 없이 인쇄합니다. .대부분의 구현에서 명령은 바이트가 아닌 청크로 입력을 읽는 것을 선호하기 때문에 다르게 작동합니다 . 그럼에도 불구하고 ewq - qwe를 완전히 제거하고 스트림 입력(예: FIFO)에서 작동합니다.

qwe
asd
xca
asdfarrf
sxcad
asdfa
sdca
dac
dacqa
ea
sdcv
asgfa
sdcv
qwe
a
df
fa
vas
fg
fasdf
qwe
aefawasd
adfae
asdfwe
asdf
era
fbn
tsgnjd
nuydid
hyhnydf
gby
asfga
dsg
qwe
rtargt
raga
adfgasgaa
asgarhsdtj
shyjuysy
sdgh
jstht
qwe
asfdg5ab
fgshtsadtyh
wafbvg
nasfga
ghafg
qwe
afghta
asg56ang
adfg643
5aasdfgr5
asdfg
fdagh5t

답변4

sed '/./=' input2.file | sed -n '/./N;s/\n/  /; /qwe/,/ewq/p'

관련 정보