변수에 값을 할당하여 파일을 한 줄씩 읽습니다.


752

다음 .txt 파일이 있습니다.

Marco
Paolo
Antonio

한 줄씩 읽고 싶습니다. 각 줄마다 .txt 줄 값을 변수에 할당하고 싶습니다. 내 변수가이라고 가정하면 $name흐름은 다음과 같습니다.

  • 파일에서 첫 번째 줄 읽기
  • 할당 $name= "마르코"
  • 몇 가지 작업을 수행 $name
  • 파일에서 두 번째 줄 읽기
  • Assign $name= "Paolo"


3
그 질문들이 어떻게 든 병합 될 수 있습니까? 둘 다 문제의 다른 측면을 강조하는 정말 좋은 답변을 가지고 있으며, 나쁜 답변은 그들에 대한 나쁜 점에 대한 설명에 깊이있는 설명이 있으며, 현재로서는 당신의 답변에서 고려해야 할 사항에 대한 전체 개요를 얻을 수 없습니다. 쌍에서 하나의 질문. 2 페이지 이상으로 스폰되지 않고 한 곳에 두는 것이 도움이 될 것입니다.
Egor Hans

답변:


1357

다음은 한 줄씩 인수로 전달 된 파일을 읽습니다.

while IFS= read -r line; do
    echo "Text read from file: $line"
done < my_filename.txt

이것은 루프에서 파일에서 행을 읽는 표준 형식 입니다. 설명:

  • IFS=(또는 IFS='') 선행 / 후행 공백이 잘리지 않도록합니다.
  • -r 백 슬래시 이스케이프가 해석되지 않도록합니다.

또는 bash 파일 도우미 스크립트 (예제 내용)에 넣을 수 있습니다.

#!/bin/bash
while IFS= read -r line; do
    echo "Text read from file: $line"
done < "$1"

위의 파일 이름이 filename으로 스크립트에 저장 readfile되면 다음과 같이 실행할 수 있습니다.

chmod +x readfile
./readfile filename.txt

파일이 표준 POSIX 텍스트 파일이 아닌 경우 (= 개행 문자로 끝나지 않음) 후행 부분 행을 처리하도록 루프를 수정할 수 있습니다.

while IFS= read -r line || [[ -n "$line" ]]; do
    echo "Text read from file: $line"
done < "$1"

여기 || [[ -n $line ]]에서 마지막 줄이 E로 끝나지 않으면 0이 아닌 종료 코드를 반환 \n하므로 끝으로 무시되지 않도록 read합니다.

루프 내부의 명령이 표준 입력에서도 읽히는 경우에 사용되는 파일 디스크립터 read는 다른 표준 파일 디스크립터를 피할 수 있습니다 . 예를 들면 다음과 같습니다.

while IFS= read -r -u3 line; do
    echo "Text read from file: $line"
done 3< "$1"

비 Bash 쉘은 알지 못할 수도 read -u3있으므로 read <&3대신 사용하십시오.


23
이 방법에는 경고가 있습니다. while 루프 내부의 내용이 대화 형인 경우 (예 : stdin에서 읽음) $ 1에서 입력을받습니다. 데이터를 수동으로 입력 할 기회가 없습니다.
carpie

10
참고로-일부 명령은 루프를 끊습니다. 예를 들어, 플래그가 ssh없으면 -n효과적으로 루프를 벗어날 수 있습니다. 아마도 이것에 대한 좋은 이유가 있지만 이것을 발견하기 전에 코드가 실패하는 원인을 알아내는 데 시간이 걸렸습니다.
Alex

6
단일 라이너로 : IFS = ''동안 -r line || [[-n "$ line"]]; "$ line"을 반향하십시오; done <filename
Joseph Johnson

8
@ OndraŽižka는 ffmpegstdin 을 소비 하여 발생합니다 . 추가 </dev/null사용자에 ffmpeg라인이 수에, 또는 루프에 대한 대체 FD를 사용하지 않습니다. "대체 FD"접근 방식은 다음과 같습니다 while IFS='' read -r line <&3 || [[ -n "$line" ]]; do ...; done 3<"$1".
Charles Duffy

9
grumble re : .sh확장 권고 . UNIX의 실행 파일에는 일반적으로 확장 기능이 전혀 없으며 (실행하지 않음 ls.elf) bash shebang (및 같은 bash 전용 툴링 [[ ]]) 및 POSIX sh 호환성을 암시하는 확장 기능은 내부적으로 모순됩니다.
Charles Duffy

309

다음을 나타내는 -r플래그 를 사용하는 것이 좋습니다 read.

-r  Do not treat a backslash character in any special way. Consider each
    backslash to be part of the input line.

에서 인용하고 man 1 read있습니다.

또 다른 것은 파일 이름을 인수로 취하는 것입니다.

업데이트 된 코드는 다음과 같습니다.

#!/usr/bin/bash
filename="$1"
while read -r line; do
    name="$line"
    echo "Name read from file - $name"
done < "$filename"

4
선도 라인에서 공간을 후행 트림
barfuin

@Thomas와 중간의 공백은 어떻게됩니까? 힌트 : 원하지 않는 명령 실행을 시도했습니다.
kmarsh

1
이것은 받아 들인 대답과 달리 나를 위해 일했습니다.
신경 전달 물질

3
@TranslucentCloud, 이것이 효과가 있고 허용 된 답변이 효과가 없다면 쉘이 sh아닌 것 같습니다 bash. || [[ -n "$line" ]]허용되는 답변 의 구문에 사용 된 확장 테스트 명령 은 bashism입니다. 즉,이 구문은 실제로 의미가 있습니다. 줄 바꿈이 없어도 입력 파일의 마지막 줄에 대해 루프가 계속됩니다. POSIX 호환 방식으로 원한다면 || [ -n "$line" ]을 사용 하고 싶을 [[[입니다.
Charles Duffy

3
즉,이가 말했다 않습니다 여전히 세트로 수정해야 IFS=에 대한 read공백을 트리밍 방지 할 수 있습니다.
Charles Duffy

132

다음 Bash 템플릿을 사용하면 파일에서 한 번에 하나의 값을 읽고 처리 할 수 ​​있습니다.

while read name; do
    # Do what you want to $name
done < filename

14
하나의 라이너로 : 이름을 읽는 동안; echo $ {name}; done <filename
Joseph Johnson

4
@CalculusKnight, 테스트하기에 충분히 흥미로운 데이터를 사용하지 않았기 때문에 "작동했습니다". 백 슬래시가 있거나을 포함하는 행이있는 컨텐츠를 사용해보십시오 *.
Charles Duffy

7
@Matthias, 결국 거짓으로 판명 된 가정은 보안에 영향을 미치는 것과 그렇지 않은 경우에 가장 큰 버그의 원인 중 하나입니다. 내가 본 것 중 가장 큰 데이터 손실 이벤트는 누군가가 "문학적으로 절대 일어나지 않을 것"이라고 가정 한 시나리오 때문입니다. 즉, 임의의 메모리를 파일 이름을 지정하는 데 사용되는 버퍼에 덤핑하는 버퍼 오버플로 매우 가지고 발생하는 매우 불행한 행동을.
Charles Duffy

5
@Matthias, ... StackOverflow에 표시된 코드 샘플은 사람들이 자신의 작업에서 패턴을 재사용 할 수 있도록 교육 도구로 사용되기 때문에 특히 그렇습니다!
Charles Duffy

5
@Matthias, 나는 "원하는 데이터에 대해서만 코드를 고안해야한다"는 주장에 전적으로 동의하지 않습니다. 예기치 않은 경우는 버그가 있고 보안 취약점이있는 경우입니다. 처리는 슬래시 코드와 강력한 코드의 차이입니다. 물론, 처리가 멋질 필요는 없습니다. 단지 "오류와 함께 종료"될 수 있습니다. 그러나 처리가 전혀 없다면 예기치 않은 경우의 행동은 정의되지 않습니다.
찰스 더피

76
#! /bin/bash
cat filename | while read LINE; do
    echo $LINE
done

8
다른 답변에 반대하는 것은 없으며 아마도 더 답답할 수도 있지만이 답변은 간단하고 읽기 쉽고 충분하기 때문에 충분합니다. 작동하려면 읽을 텍스트 파일이 빈 줄로 끝나야합니다 (즉 Enter, 마지막 줄 다음 에 눌러야 함 ). 그렇지 않으면 마지막 줄이 무시됩니다. 적어도 그것이 저에게 일어난 일입니다.
Antonio Vinicius Menezes Medei

12
고양이의 쓸모없는 사용, 당연하지?
Brian Agnew

5
그리고 인용이 깨졌습니다. 대문자 변수 이름은 시스템 용으로 예약되어 있으므로 사용하지 않아야합니다.
tripleee

7
@AntonioViniciusMenezesMedei, ... 또한 사람들은 이러한 경고가 결코 중요하지 않다고 생각하기 때문에 재정적 손실을 입는 것을 보았습니다. 모범 사례를 배우지 못했습니다. 그런 다음 중요한 청구 데이터의 백업을 관리하는 스크립트를 작성할 때 사용했던 습관을 따랐습니다. 올바른 일을하는 법을 배우는 것이 중요합니다.
Charles Duffy

6
여기서 또 다른 문제는 파이프가 새로운 서브 쉘을 여는 것입니다. 즉, 루프 내부에 설정된 모든 변수는 루프가 끝난 후에 읽을 수 없습니다.
mxmlnkn

20

많은 사람들이 과도하게 최적화 된 솔루션을 게시했습니다. 나는 그것이 틀렸다고 생각하지 않지만 겸손하게 모든 사람들 이이 작동 방식을 쉽게 이해할 수 있도록 덜 최적화 된 솔루션이 바람직하다고 생각합니다. 내 제안은 다음과 같습니다.

#!/bin/bash
#
# This program reads lines from a file.
#

end_of_file=0
while [[ $end_of_file == 0 ]]; do
  read -r line
  # the last exit status is the 
  # flag of the end of file
  end_of_file=$?
  echo $line
done < "$1"

20

사용하다:

filename=$1
IFS=$'\n'
for next in `cat $filename`; do
    echo "$next read from $filename" 
done
exit 0

IFS다르게 설정 하면 이상한 결과가 나타납니다.


34
이것은 끔찍한 방법 입니다. 인식하기 전에 발생할 수있는 글러브 문제가 발생하지 않는 한 사용하지 마십시오!
gniourf_gniourf 12

13
@MUYBelgium *한 줄에 단일 파일이 들어있는 파일로 시도 했 습니까? 어쨌든 이것은 반 패턴 입니다. for로 줄을 읽지 마십시오 .
gniourf_gniourf 16:14에

2
@ OndraŽižka,이 read접근법은 지역 사회 합의에 의한 모범 사례 접근법 입니다. 주석에서 언급 한주의 사항은 루프가 ffmpegstdin에서 읽은 명령 (예 :)을 실행할 때 적용되며 루프에 stdin이 아닌 FD를 사용하거나 이러한 명령의 입력을 리디렉션하여 사소하게 해결됩니다. 반대로, for-loop 방식 에서 글 로빙 버그를 해결하려면 셸 전역 설정을 변경 한 다음 되돌려 야합니다.
Charles Duffy

1
OndraŽižka @ ... 또한, for루프 접근 방식은 당신이 경우에도 기가 바이트의 데이터가 이상 반복하는 경우는 완전히 사용할 수 없게 모든 콘텐츠는 루프가 전혀 실행을 시작하기 전에 읽어야한다는 것을 여기에 방법을 사용 불가능 글 로빙; while read루프는 하위 프로세스 생성 콘텐츠가 아직 실행 중에 (즉 목적 스트리밍 가능한 임) 실행을 시작할 수 있다는 것을 의미하는 시간에 더 이상 단일 행의 데이터보다 저장할 필요가 없으며, 또한 제한된 메모리 소비를 갖는다.
Charles Duffy

1
실제로, 심지어 while기반 접근 방식에는 * 문자 문제가있는 것으로 보입니다. 위의 답변에 대한 의견을 참조하십시오. 그러나 반 패턴 인 파일에 대한 반복을 반대하지는 않는다.
Egor Hans

9

입력 파일과 사용자 입력 (또는 stdin의 다른 것)을 모두 처리해야하는 경우 다음 해결 방법을 사용하십시오.

#!/bin/bash
exec 3<"$1"
while IFS='' read -r -u 3 line || [[ -n "$line" ]]; do
    read -p "> $line (Press Enter to continue)"
done

허용 된 답변bash-hackers 리디렉션 자습서를 기반으로 합니다 .

여기서 스크립트 인수로 전달 된 파일에 대해 파일 설명자 3을 열고이 read설명자를 입력 ( -u 3) 으로 사용하도록 지시합니다 . 따라서 기본 입력 설명자 (0)를 터미널이나 다른 입력 소스에 연결하여 사용자 입력을 읽을 수 있습니다.


7

올바른 오류 처리를 위해

#!/bin/bash

set -Ee    
trap "echo error" EXIT    
test -e ${FILENAME} || exit
while read -r line
do
    echo ${line}
done < ${FILENAME}

설명을 추가해 주시겠습니까?
Tyler Christian

불행히도 파일의 마지막 줄이 없습니다.
ungalcrys

... 또한 인용 부족으로 인해 BashPitfalls # 14에 설명 된대로 와일드 카드를 포함하는 줄을 줄입니다 .
찰스 더피

0

다음은 파일 내용을 인쇄합니다.

cat $Path/FileName.txt

while read line;
do
echo $line     
done

1
이 답변은 실제로 기존 답변보다 아무것도 추가하지 않으며 오타 / 버그로 인해 작동하지 않으며 여러 가지 방법으로 중단됩니다.
Konrad Rudolph

0

bash에서 IFS (내장 필드 구분 기호) 도구를 사용하고, 줄을 토큰으로 구분하는 데 사용하는 문자를 정의합니다. 기본적으로 < tab > / < space > / < newLine >

1 단계 : 파일 데이터를로드하고 목록에 삽입하십시오.

# declaring array list and index iterator
declare -a array=()
i=0

# reading file in row mode, insert each line into array
while IFS= read -r line; do
    array[i]=$line
    let "i++"
    # reading from file path
done < "<yourFullFilePath>"

2 단계 : 이제 출력을 반복하고 인쇄합니다.

for line in "${array[@]}"
  do
    echo "$line"
  done

배열의 에코 특정 인덱스 : 배열 의 변수에 액세스 :

echo "${array[0]}"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.