programing

Bash에서 파일 내용을 루프하는 중

lovejava 2023. 4. 9. 20:54

Bash에서 파일 내용을 루프하는 중

Bash를 사용하여 텍스트 파일의 각 행을 반복하려면 어떻게 해야 합니까?

이 스크립트의 경우:

echo "Start!"
for p in (peptides.txt)
do
    echo "${p}"
done

화면에 다음과 같은 출력이 표시됩니다.

Start!
./runPep.sh: line 3: syntax error near unexpected token `('
./runPep.sh: line 3: `for p in (peptides.txt)'

에 좀 더 것을 .$p을 참조해 주십시오.)


환경변수 SHEL은 (env에서) 다음과 같습니다.

SHELL=/bin/bash

/bin/bash --version★★★★

GNU bash, version 3.1.17(1)-release (x86_64-suse-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.

cat /proc/version★★★★

Linux version 2.6.18.2-34-default (geeko@buildhost) (gcc version 4.1.2 20061115 (prerelease) (SUSE Linux)) #1 SMP Mon Nov 27 11:46:27 UTC 2006

파일이 펩타이드화 됩니다.txt의 내용:

RKEKNVQ
IPKKLLQK
QYFHQLEKMNVK
IPKKLLQK
GDLSTALEVAIDCYEK
QYFHQLEKMNVKIPENIYR
RKEKNVQ
VLAKHGKLQDAIN
ILGFMK
LEDVALQILL

한 가지 방법은 다음과 같습니다.

while read p; do
  echo "$p"
done <peptides.txt

코멘트에서 지적된 바와 같이, 이것은 선행 공백을 잘라내고, 백슬래시 시퀀스를 해석하고, 끝줄 피드가 없는 경우 마지막 줄을 건너뛸 수 있는 부작용이 있습니다.문제가 있는 경우는, 다음의 작업을 실시할 수 있습니다.

while IFS="" read -r p || [ -n "$p" ]
do
  printf '%s\n' "$p"
done < peptides.txt

예외적으로 루프 본문이 표준 입력에서 읽을있는 경우 다른 파일 기술자를 사용하여 파일을 열 수 있습니다.

while read -u 10 p; do
  ...
done 10<peptides.txt

여기서 10은 그냥 임의의 숫자입니다(0, 1, 2와는 다릅니다).

cat peptides.txt | while read line 
do
   # do something with $line here
done

및 원라이너 모델:

cat peptides.txt | while read line; do something_with_$line_here; done

이러한 옵션은 후행 피드가 없는 경우 파일의 마지막 줄을 건너뜁니다.

이 문제를 회피할 수 있는 방법은 다음과 같습니다.

cat peptides.txt | while read line || [[ -n $line ]];
do
   # do something with $line here
done

옵션 1a: 루프 중: 한 번에 한 줄씩:입력 리다이렉션

#!/bin/bash
filename='peptides.txt'
echo Start
while read p; do 
    echo "$p"
done < "$filename"

옵션 1b: 루프 중: 한 번에 한 줄씩:
파일 디스크립터(이 경우는 파일 디스크립터 #4)에서 읽어낸 파일을 엽니다.

#!/bin/bash
filename='peptides.txt'
exec 4<"$filename"
echo Start
while read -u4 p ; do
    echo "$p"
done

이는 다른 답변과 다를 바 없지만 공백이 없는 파일에서 작업을 수행하는 또 다른 방법입니다(댓글 참조).스크립트 파일을 따로 사용하지 않고 텍스트 파일의 목록을 한 줄씩 읽어야 하는 경우가 많습니다.

for word in $(cat peptides.txt); do echo $word; done

이 형식을 사용하면 모든 것을 하나의 명령줄에 저장할 수 있습니다."echo $word" 부분을 원하는 대로 변경하면 세미콜론으로 구분된 여러 명령을 실행할 수 있습니다.다음 예제에서는 파일 내용을 인수로 사용하여 작성한 다른 두 스크립트에 대한 내용을 보여 줍니다.

for word in $(cat peptides.txt); do cmd_a.sh $word; cmd_b.py $word; done

또는 이것을 스트림에디터(learn sed)와 같이 사용하는 경우는, 다음과 같이 출력을 다른 파일에 덤프 할 수 있습니다.

for word in $(cat peptides.txt); do cmd_a.sh $word; cmd_b.py $word; done > outfile.txt

한 줄에 한 단어로 작성한 텍스트 파일을 사용한 적이 있기 때문에 위와 같이 사용하고 있습니다.(댓글 참조) 단어/줄을 분할하지 않는 공백이 있는 경우, 조금 더 보기 흉해지지만 동일한 명령어는 다음과 같이 작동합니다.

OLDIFS=$IFS; IFS=$'\n'; for line in $(cat peptides.txt); do cmd_a.sh $line; cmd_b.py $line; done > outfile.txt; IFS=$OLDIFS

이렇게 하면 셸이 공백이 아닌 줄바꿈으로만 분할하도록 지시하고 환경을 이전 상태로 되돌립니다.다만, 이 시점에서, 모든 것을 한 줄에 짜넣는 것보다, 셸 스크립트에 짜넣는 것을 고려해 보는 것이 좋을지도 모릅니다.

행운을 빌어요!

다른 답변에서는 다루지 않는 몇 가지 사항이 더 있습니다.

구분된 파일에서 읽기

# ':' is the delimiter here, and there are three fields on each line in the file
# IFS set below is restricted to the context of `read`, it doesn't affect any other code
while IFS=: read -r field1 field2 field3; do
  # process the fields
  # if the line has less than three fields, the missing fields will be set to an empty string
  # if the line has more than three fields, `field3` will get all the values, including the third field plus the delimiter(s)
done < input.txt

프로세스 대체를 사용하여 다른 명령어 출력에서 읽기

while read -r line; do
  # process the line
done < <(command ...)

이 더 command ... | while read -r line; do ...왜냐하면 여기서 while 루프는 후자의 경우와 같이 서브셸이 아닌 현재 셸에서 실행되기 때문입니다.루프가 기억되지 않는 동안 내부에서 변경된 변수는 관련 게시물을 참조해당 게시물은 다음과 같습니다.

입력: Null " " " " )에서 .find ... -print0

while read -r -d '' line; do
  # logic
  # use a second 'read ... <<< "$line"' if we need to tokenize the line
done < <(find /path/to/dir -print0)

관련: BashFAQ/020 - 줄 바꿈, 공백 또는 다 포함된 파일 이름을 검색하여 안전하게 처리하는 방법 확인.

한 번에 두 개 이상의 파일에서 읽기

while read -u 3 -r line1 && read -u 4 -r line2; do
  # process the lines
  # note that the loop will end when we reach EOF on either of the files, because of the `&&`
done 3< input1.txt 4< input2.txt

여기 @chepner답변 근거합니다.

-u쾅쾅 때리다의 경우,각은 POSIX 「」와 .read -r X <&3.

파일 전체를 어레이로 읽기 (4 이전 버전의 Bash)

while read -r line; do
    my_array+=("$line")
done < my_file

파일이 불완전한 행(마지막에 줄바꿈이 누락됨)으로 끝나는 경우:

while read -r line || [[ $line ]]; do
    my_array+=("$line")
done < my_file

파일 전체를 어레이로 읽기(Bash 버전 4x 이후)

readarray -t my_array < my_file

또는

mapfile -t my_array < my_file

그리고 나서.

for line in "${my_array[@]}"; do
  # process the lines
done

관련 투고:

다음과 같이 while loop을 사용합니다.

while IFS= read -r line; do
   echo "$line"
done <file

주의:

  1. IFS제대로 하면 움푹 패인 부분이 없어집니다.

  2. 읽기에는 거의 항상 -r 옵션을 사용해야 합니다.

  3. 읽다, 읽으면 안 요.for

읽기를 줄바꿈 문자로 구분하지 않으려면 다음을 사용하십시오.

#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
    echo "$line"
done < "$1"

그런 다음 파일 이름을 매개 변수로 하여 스크립트를 실행합니다.

다음과 같은 파일이 있다고 가정합니다.

$ cat /tmp/test.txt
Line 1
    Line 2 has leading space
Line 3 followed by blank line

Line 5 (follows a blank line) and has trailing space    
Line 6 has no ending CR

많은 Bash 솔루션에 의해 읽혀지는 파일 출력의 의미를 변경하는 4가지 요소가 있습니다.

  1. 빈 줄 4;
  2. 두 줄의 선행 또는 후행 공간
  3. 개별 라인의 의미 유지(즉, 각 라인은 기록)
  4. 회선 6이 CR로 종단되지 않았습니다.

CR 없이 빈 줄과 끝 줄을 포함하는 텍스트 파일을 한 줄씩 보려면 while loop을 사용하고 최종 줄에 대한 대체 테스트를 수행해야 합니다.

할 수 .cat( ) :

1) 마지막 줄과 선행 및 후행 공백이 없어집니다.

$ while read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
'Line 1'
'Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space'

경우)while IFS= read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt및되지 않은 경우 이 손실됩니다.

2) 2) 프로세스 대체 cat1kg의 전체 파일을 읽으며 개별 라인의 의미를 잃게 됩니다.파일 전체를 단숨에 읽어내 각 행의 의미를 잃게 됩니다.

$ for p in "$(cat /tmp/test.txt)"; do printf "%s\n" "'$p'"; done
'Line 1
    Line 2 has leading space
Line 3 followed by blank line

Line 5 (follows a blank line) and has trailing space    
Line 6 has no ending CR'

()) 제) 우 했 경) ,"부에서$(cat /tmp/test.txt)한 마디보다는 파일 단어를 읽습니다.한 번에 읽는 것보다 한 단어씩 읽는 거야.또한, 도... is또) also probably) not것 intended모아...도만 what다니?


파일을 한 줄씩 읽고 모든 간격을 유지하는 가장 강력하고 간단한 방법은 다음과 같습니다.

$ while IFS= read -r line || [[ -n $line ]]; do printf "'%s'\n" "$line"; done </tmp/test.txt
'Line 1'
'    Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space    '
'Line 6 has no ending CR'

선두와 거래 공간을 분리하려면 두 래 간 거 하 을 려 if you and the면 spaces leading trading)IFS= 삭제:

$ while read -r line || [[ -n $line ]]; do printf "'%s'\n" "$line"; done </tmp/test.txt
'Line 1'
'Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space'
'Line 6 has no ending CR'

)\n포식스에 오는 것을 수 \n 없다|| [[ -n $line ]] while를 선택합니다.

자세한 내용은 BASH FAQ를 참조하십시오.

사용하는 것을 좋아합니다.xargswhilexargs line 친화적입니다.

cat peptides.txt | xargs -I % sh -c "echo %"

★★★★★★★★★★★★★★★★ xargs에을 더할 도 있습니다.-tvalid및 검 ation and -p

이것이 가장 간단한 답변일 수도 있고 모든 경우에 효과가 있는 것은 아닐 수도 있지만, 나에게는 매우 효과적입니다.

while read line;do echo "$line";done<peptides.txt

공백 괄호로 둘러싸야 하는 경우:

while read line;do echo \"$line\";done<peptides.txt

아, 이것은 가장 많이 투표된 답변과 거의 비슷하지만, 모두 한 줄에 있습니다.

#!/bin/bash
#
# Change the file name from "test" to desired input file 
# (The comments in bash are prefixed with #'s)
for x in $(cat test.txt)
do
    echo $x
done

다른 프로그램 출력의 행을 루프하고, 서브스트링을 체크하고, 변수에서 큰따옴표를 삭제하고, 해당 변수를 루프 밖에서 사용하는 예를 소개합니다.많은 분들이 조만간 이런 질문을 하실 것 같아요.

##Parse FPS from first video stream, drop quotes from fps variable
## streams.stream.0.codec_type="video"
## streams.stream.0.r_frame_rate="24000/1001"
## streams.stream.0.avg_frame_rate="24000/1001"
FPS=unknown
while read -r line; do
  if [[ $FPS == "unknown" ]] && [[ $line == *".codec_type=\"video\""* ]]; then
    echo ParseFPS $line
    FPS=parse
  fi
  if [[ $FPS == "parse" ]] && [[ $line == *".r_frame_rate="* ]]; then
    echo ParseFPS $line
    FPS=${line##*=}
    FPS="${FPS%\"}"
    FPS="${FPS#\"}"
  fi
done <<< "$(ffprobe -v quiet -print_format flat -show_format -show_streams -i "$input")"
if [ "$FPS" == "unknown" ] || [ "$FPS" == "parse" ]; then 
  echo ParseFPS Unknown frame rate
fi
echo Found $FPS

루프 외부에서 변수를 선언하고 값을 설정하고 루프 외부에서 사용하려면 done << "$(...)" 구문이 필요합니다.응용 프로그램은 현재 콘솔의 컨텍스트 내에서 실행해야 합니다.명령어 주위에 따옴표를 붙이면 출력 스트림의 새로운 행이 유지됩니다.

하위 문자열에 대한 루프 일치는 name=value pair를 읽고, 마지막 = 문자의 오른쪽 부분을 분할하고, 첫 번째 따옴표를 삭제하고, 마지막 따옴표를 삭제하며, 다른 곳에서 사용할 깨끗한 값을 제공합니다.

조금 늦었지만 누군가에게 도움이 될지도 모른다는 생각에 답변을 덧붙입니다.또한 이것이 최선의 방법이 아닐 수도 있습니다. head는 명어는 command command command command command command command command command command 와 함께 사용할 수 .-n파일 시작부터n 읽는 인수 등tail명령어를 사용하여 아래에서 읽을 수 있습니다.파일에서 n번째 행을 가져오려면 n개의 행을 선두로 하고 데이터를 파이핑된 데이터에서 한 줄만 테일링합니다.

   TOTAL_LINES=`wc -l $USER_FILE | cut -d " " -f1 `
   echo $TOTAL_LINES       # To validate total lines in the file

   for (( i=1 ; i <= $TOTAL_LINES; i++ ))
   do
      LINE=`head -n$i $USER_FILE | tail -n1`
      echo $LINE
   done

@Peter: 잘 될 것 같은데...

echo "Start!";for p in $(cat ./pep); do
echo $p
done

그러면 출력이 반환됩니다.

Start!
RKEKNVQ
IPKKLLQK
QYFHQLEKMNVK
IPKKLLQK
GDLSTALEVAIDCYEK
QYFHQLEKMNVKIPENIYR
RKEKNVQ
VLAKHGKLQDAIN
ILGFMK
LEDVALQILL

xargs를 사용하는 또 다른 방법

<file_name | xargs -I {} echo {}

echo는 다른 명령어로 대체하거나 더 많은 파이프를 연결할 수 있습니다.

p in 'cat 펩타이드.txt가 "${p}"를 에코합니다.

언급URL : https://stackoverflow.com/questions/1521462/looping-through-the-content-of-a-file-in-bash