Bash 배열에서 매개 변수 대체 사용

Bash 배열로 읽어야하는 file.txt가 있습니다. 그런 다음 공백, 큰 따옴표 및 모든 항목의 첫 번째 쉼표를 제외한 모든 항목 을 제거해야합니다. 내가 얼마나 멀리 왔는지 :

$ cat file.txt 10,this 2 0 , i s 30,"all" 40,I 50,n,e,e,d,2 60",s e,e" $ cat script.sh #!/bin/bash readarray -t ARRAY<$1 ARRAY=( "${ARRAY[@]// /}" ) ARRAY=( "${ARRAY[@]//\"/}" ) for ELEMENT in "${ARRAY[@]}";do echo "|ELEMENT|$ELEMENT|" done $ ./script.sh file.txt |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,n,e,e,d,2| |ELEMENT|60,se,e| 

쉼표 상황을 제외하고는 잘 작동합니다. 이 고양이를 스킨하는 방법에는 여러 가지가 있지만이 부분이 포함 된 더 큰 스크립트로 인해 여기에 도달하기 위해 매개 변수 대체를 사용하고 싶습니다.

|ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see| 

매개 변수 대체를 통해 가능합니까?

댓글

  • 텍스트를 유지해야하는 이유가 있습니까? 배열, 그리고 왜 ' 예를 들어 awk 또는 sed가 데이터를 처리합니까?
  • @Jeff-배열을 반복하는 것은 더 큰 스크립트에서 구현하기에는 악몽이 있습니다. ' 작업 중입니다.
  • @JonRed ' 그래서 ' 문제에 대해 선택의 여지가 없을 수도 있지만 일반적으로 쉘에서 복잡한 문자열 곡예를 수행하는 자신을 발견하면 ' div id = “fb841fb5b8″>

실제 프로그래밍 언어를 사용해야한다는 매우 좋은 표시입니다. 셸은 프로그래밍 언어로 설계되지 않았으며 하나로 사용할 수는 있지만 실제로는 ' 더 복잡한 작업에 적합하지 않습니다. perl이나 python 또는 다른 스크립팅 언어로 전환 할 것을 강력히 권합니다.

  • @terdon It ' 재밌습니다. 이 게시물을 읽기 전에 동료에게도 마찬가지입니다. 기본적으로 이것이이 스크립트의 최종 버전이며 추가 요구 사항이 있으면 Perl로 다시 작성해야한다고 말했습니다. 네, 확실히 동의합니다
  • 답변

    sed 배열로로드하기 (또한 소문자 변수 이름에 유의하십시오. 일반적으로 쉘 스크립트에서 대문자 변수를 사용하지 않는 것이 가장 좋습니다) :

    #!/bin/bash readarray -t array< <(sed "s/"//g; s/ *//g; s/,/"/; s/,//g; s/"/,/" "$1") for element in "${array[@]}";do echo "|ELEMENT|$element|" done 

    예제 파일에 다음 출력이 생성됩니다.

    $ foo.sh file |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see| 

    매개 변수를 꼭 사용해야하는 경우 대체, 다음과 같이 시도하십시오.

    #!/bin/bash readarray -t array< "$1" array=( "${array[@]// /}" ) array=( "${array[@]//\"/}" ) array=( "${array[@]/,/\"}" ) array=( "${array[@]//,/}" ) array=( "${array[@]/\"/,}" ) for element in "${array[@]}"; do echo "|ELEMENT|$element|" done 

    댓글

    • @JonRed 매개 변수가있는 버전을 추가했습니다. 대체하지만 ' 복잡하고 번거롭고보기 흉합니다. 셸에서 이런 종류의 작업을 수행하는 것은 아주 드물게 좋은 생각입니다.
    • 공백과 큰 따옴표를 모두 제거한 경우 '이 문자를 사용할 수 있습니다. RANDOMTEXTTHATWILLNEVERBEINTHEFILE 대신 사용합니다.
    • @Kusalananda 예, 방금 답변을 읽었습니다. 그것을 생각 했어야했다! 감사합니다 🙂
    • 질문에 직접 답변하고 내가 선호하는 솔루션이 ' 이상적이지 않은 이유를 설명하고 가장 실행 가능한 대안을 제공합니다. 우수 답변입니다.

    답변

    내가 볼 수있는 한 bash 배열로 읽어서 해당 출력을 만듭니다.

    $ sed "s/[ "]//g; s/,/ /; s/,//g; s/ /,/; s/.*/|ELEMENT|&|/" <file |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see| 

    sed 표현식은 공백과 큰 따옴표를 삭제하고, 첫 번째 쉼표를 공백으로 바꾸고 (현재 문자열에 다른 공백이 없음) 다른 모든 쉼표를 삭제하고, 첫 번째 쉼표를 복원하고, 추가 데이터를 앞에 추가하고 추가합니다. .

    또는 GNU sed :

    sed "s/[ "]//g; s/,//2g; s/.*/|ELEMENT|&|/" <file 

    (표준 sed2g의 조합을 명령).

    코멘트

    • GNU sed에서는 's/,//2g를 사용할 수 있습니다. 쉼표를 제거하려면 두 번째로 시작
    • 그리고 마지막 2 개의 s /// 명령은 s/.*/|ELEMENT|&|/하지만 sed에게는 더 많은 노력이 필요할 수 있습니다.
    • @glennjackman 아마도 깔끔하게 보입니다.
    • 예, 이것은 더 큰 대본의 일부입니다. 배열은 출력뿐만 아니라 필요합니다. 따라서 매개 변수 대체에 관심이 있습니다. 나는 이것으로 배열을 반복 할 수 있지만 구현하기에는 악몽이 될 것입니다. Terndon은 sed를 사용하여 루프가없는 솔루션을 제공했습니다. 매개 변수 대체가 중단되지 않으면 ' 대체 할 가능성이 높습니다.
    • 그렇지 않은 경우 ' 배열 사용과 관련이 없지만 이것이 최상의 솔루션입니다.

    답변

    ELEMENT="50,n,e,e,d,2" IFS=, read -r first rest <<<"$ELEMENT" printf "%s,%s\n" "$first" "${rest//,/}" 
    50,need2 

    ALLCAPS 변수 이름을 사용하는 습관에서 벗어나십시오. 결국 PATH와 같은 중요한 “시스템”변수와 충돌하여 코드가 손상됩니다.

    설명

    • 매개 변수 대체가 아닙니다. 그러나 나는 ALLCAPS 변수 이름이 Bash에서 나쁜 습관이라는 것을 알지 못했습니다. 당신은 좋은 지적을하는데, 피상적 인 인터넷 검색이 확실히 확인하는 것입니다. 제 스타일을 개선 해주셔서 감사합니다! 🙂
    • ' 그 사람이 PATH=something; ls $PATH를 작성한 질문에 답변 한 다음 ls: command not found 오류.
    • 모두 대문자로 명명 된 거의 100 개의 기본 제공 변수가 있습니다 (이 매뉴얼 페이지를 클릭하여 링크 ) 볼 수 있습니다 …

    답변

    [이것은 본질적으로 더 완벽하게 개발 된 glenn jackmann “s answer ]

    첫 번째 쉼표를 구분 기호로 사용하여 제거 된 키와 값에서 연관 배열 만들기 :

    declare -A arr while IFS=, read -r k v; do arr["${k//[ \"]}"]="${v//[ ,\"]}"; done < file.txt for k in "${!arr[@]}"; do printf "|ELEMENT|%s,%s|\n" "$k" "${arr[$k]}" done |ELEMENT|20,is| |ELEMENT|10,this| |ELEMENT|50,need2| |ELEMENT|40,I| |ELEMENT|60,see| |ELEMENT|30,all| 

    Answer

    배열을 반복하고 중간 변수를 사용할 수 있습니다.

    for((i=0; i < "${#ARRAY[@]}"; i++)) do rest="${ARRAY[i]#*,}" ARRAY[i]="${ARRAY[i]%%,*}","${rest//,/}" done 

    첫 번째 쉼표 뒤의 부분을 rest에 할당 한 다음 세 부분을 다시 원본에 연결합니다. 변수 :

    • 첫 번째 쉼표 앞 부분
    • 쉼표
    • rest의 모든 쉼표에서 아무것도없는 대체

    댓글

    • 이것은 저의 첫 번째 생각이었고 예제에서는 충분히 간단하지만 이것은 배열이 방대하고 이미 루프가 있고 ' 전체가되는 큰 스크립트의 일부입니다. 이것은 확실히 작동 할 것이지만 작업중인 더 큰 프로젝트에서 ' 구현하기에는 매우 번거 롭습니다.
    • 충분합니다. 제한 범위 내에서 답변하려고했습니다 (매개 변수 확장 만 해당).

    답글 남기기

    이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다