Bash의 텍스트 파일에서 배열 만들기


88

스크립트는 URL을 가져 와서 필수 필드에 대해 구문 분석하고 출력을 리디렉션하여 file.txt 파일에 저장합니다 . 출력은 필드가 발견 될 때마다 새 줄에 저장됩니다.

file.txt

A Cat
A Dog
A Mouse 
etc... 

file.txt모든 줄이 배열의 자체 문자열 변수가되는 새 스크립트에서 배열 을 가져 와서 만들고 싶습니다 . 지금까지 시도했습니다.

#!/bin/bash

filename=file.txt
declare -a myArray
myArray=(`cat "$filename"`)

for (( i = 0 ; i < 9 ; i++))
do
  echo "Element [$i]: ${myArray[$i]}"
done

이 스크립트를 실행할 때 공백으로 인해 단어가 분할되고

원하는 출력

Element [0]: A Cat 
Element [1]: A Dog 
etc... 

나는 이것을 얻는다.

실제 출력

Element [0]: A 
Element [1]: Cat 
Element [2]: A
Element [3]: Dog 
etc... 

각 줄의 전체 문자열이 배열의 각 변수와 일대일 일치하도록 아래의 루프를 어떻게 조정할 수 있습니까?


5
이것이 Bash FAQ 001의 모든 것입니다. 또한 Bash FAQ 005 에있는 배열 주제 의이 섹션 .
Etan Reisner

1
나는 이것을 stackoverflow.com/questions/11393817/… 의 복제물로 연결할 것입니다 . 그러나 받아 들여진 대답은 끔찍합니다.
Charles Duffy

Etan, 이렇게 빠르고 정확한 답변을 해주셔서 감사합니다! 포럼에서 내 질문을 검색하려고했지만 stackoverflow에 대한 FAQ를 찾을 생각은하지 않았습니다. mapfile 명령은 내 요구를 정확하게 해결했습니다! 다시 한 번 감사드립니다 :) 섹션 2.1에하십시오 .
user2856414

2
(여기에있는 것보다 더 잘 받아 들여지는 답변이 있으므로 반대 방향으로 링크를 설정하십시오).
Charles Duffy

답변:


110

다음 mapfile명령을 사용하십시오 .

mapfile -t myArray < file.txt

오류는 다음을 사용 하고 있습니다. 파일의 for 을 반복하는 관용적 인 방법 은 다음과 같습니다.

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

자세한 내용은 BashFAQ / 005 를 참조하십시오.


5
이것은 표준 Q & A로 홍보되고 있으므로 링크에 언급 된 내용을 포함 할 수도 있습니다 while IFS= read -r; do lines+=("$REPLY"); done <file..
fedorqui 'SO stop harming'2011

10
맵 파일은 4.x의 이전 bash는 버전에 존재하지 않습니다
ericslaw

14
Bash 4는 이제 약 5 년이되었습니다. 업그레이드.
glenn jackman

5
bash 4가 2009 년에 출시 되었음에도 불구하고, 많은 머신이 여전히 bash 3.x와 함께 제공되기 때문에 @ericslaw의 의견은 여전히 ​​관련이 있습니다 (배쉬가 GPLv3에 따라 출시되는 한 업그레이드되지 않을 것임). 이식성에 관심이 있다면 주목해야 할 중요한 사항입니다
De Novo

12
문제는 개발자가 업그레이드 된 버전을 설치할 수 없다는 것이 mapfile아니라 추가 단계 없이는 많은 컴퓨터에서 사용하는 스크립트 가 예상대로 실행되지 않는다는 점을 개발자가 알고 있어야한다는 것입니다. @ericslaw macs는 가까운 장래에 bash 3.2.57과 함께 계속 제공 될 것입니다. 최신 버전은 Apple이 공유하거나 허용하지 않는 것을 공유하거나 허용하는 데 필요한 라이선스를 사용합니다.
De Novo

24

mapfilereadarray(동의어있는) 배쉬 버전 4 이상에서 사용할 수 있습니다. 이전 버전의 Bash가있는 경우 루프를 사용하여 파일을 배열로 읽을 수 있습니다.

arr=()
while IFS= read -r line; do
  arr+=("$line")
done < file

파일에 불완전한 (줄 바꿈 누락) 마지막 줄이있는 경우 다음 대안을 사용할 수 있습니다.

arr=()
while IFS= read -r line || [[ "$line" ]]; do
  arr+=("$line")
done < file

관련 :


나는 그것이 IFS= read -r line || [[ "$line" ]]작동 하기 위해 괄호를 묶어야한다는 것을 알았습니다 . 그렇지 않으면 훌륭하게 작동합니다!
타티아나 Racheva

@TatianaRacheva : 이전에 누락 된 세미콜론이 do아닌가요?
codeforester

9

이 작업도 수행 할 수 있습니다.

oldIFS="$IFS"
IFS=$'\n' arr=($(<file))
IFS="$oldIFS"
echo "${arr[1]}" # It will print `A Dog`.

노트 :

파일 이름 확장이 계속 발생합니다. 예를 들어, 리터럴 *이 있는 줄이 있으면 현재 폴더의 모든 파일로 확장됩니다. 따라서 파일에 이러한 종류의 시나리오가없는 경우에만 사용하십시오.


IFS할당을 계속 유지하면서 일시적으로 만 설정하는 방법이 있습니까 (이 명령 후 원래 값을 복구하도록) arr?
Hugues

1
파일 이름 확장은 계속 발생합니다. 예IFS=$'\n' arr=($(echo 'a 1'; echo '*'; echo 'b 2')); printf "%s\n" "${arr[@]}"
Hugues

@Hugues : yap, 파일 이름 확장이 계속 발생합니다. 나는 info..thnks의 비트를 추가합니다 ..
Jahid

죄송합니다. 동의하지 않습니다. 현재 셸 IFS=... command에서는 변경되지 않습니다 IFS. 그러나 IFS=... other_variable=...(명령없이) 현재 셸 IFS과 모두 변경 other_variable됩니다.
Hugues

1
감사! 이것은 작동합니다. 내가 arr=( mapfile/에 비해 readarray) 표기법을 좋아하는 것처럼 더 간단한 방법이 없다는 것은 유감입니다 .
Hugues

4

파일에서 각 줄을 읽고 배열에 할당하기 만하면됩니다.

#!/bin/bash
i=0
while read line 
do
        arr[$i]="$line"
        i=$((i+1))
done < file.txt

1
어레이에 어떻게 액세스합니까?
hola

4

맵 파일을 사용하거나 -a를 읽으십시오.

항상 shellcheck를 사용하여 코드를 확인하십시오 . 종종 정답을 줄 것입니다. 이 경우 SC2207 은 공백으로 구분되거나 줄 바꿈으로 구분 된 값이있는 파일을 배열로 읽는 것을 다룹니다.

이러지마

array=( $(mycommand) )

줄 바꿈으로 구분 된 값이있는 파일

mapfile -t array < <(mycommand)

공백으로 구분 된 값이있는 파일

IFS=" " read -r -a array <<< "$(mycommand)"

shellcheck 페이지는 이것이 모범 사례로 간주되는 이유를 제공합니다.


0

이 대답

mapfile -t myArray < file.txt

어떤 이유로 든 bash <4.x 에서 사용하려면 shim 을 만들었습니다 . bash> = 4.x 인 경우 기존 명령을 사용합니다.mapfilemapfilemapfile

현재는 옵션 -d-t작업 만 있습니다 . 그러나 위의 명령에는 충분합니다. macOS에서만 테스트했습니다. macOS Sierra 10.12.6에서 시스템 bash는 3.2.57(1)-release. 따라서 심이 유용 할 수 있습니다. homebrew로 bash를 업데이트하고 직접 bash를 빌드 할 수도 있습니다.

이 기술 을 사용 하여 하나의 호출 스택에 변수를 설정합니다.

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