요소에 공백이 있는 bash 배열

요소에 공백이 있는 bash 배열

텍스트 로그 파일이 있습니다

$ cat aaa
673                  20160405 root "/path_to/gis/20160401/20160301_placement_map_org.dbf" ""
673                  20160405 root "/path_to/gis/20160401/20160310_20160401ent_map_org.dbf" ""
790890               20170201 jle  "/path_to/gis/20160401/Pina (Asc) 20160401 Rapid Report.kmz" ""
5883710              20160406 dho  "/path_to/gis/20160401/20160401_Pina_Asc_Rapid_Report_Minesouth.pdf" ""
673                  20160405 dho  "/path_to/gis/20160401/20160310_20160401 placement map org.dbf" ""

이제 내 스크립트는 파일의 전체 경로만 출력합니다.

#!/bin/bash

function nodatechk() {
    arr=("$@")
    for ((i=3;i<${#arr[@]};i+=5));
    do
      echo "${i}" "${arr[i]}"
    done
}

r=( $(grep gis aaa) ) 

nodatechk "${r[@]}"

세 번째 줄(및 다섯 번째 줄)에 큰따옴표가 있더라도 요소에 공백이 있기 때문에 출력이 깨졌습니다.

이 문제를 어떻게 해결할 수 있나요? (그런데, awk나 cut을 사용하여 열을 인쇄할 수 있다는 것을 알고 있지만 이 경우에는 grep을 사용하고 싶습니다.) 감사합니다.

답변1

문제의 근본 원인은 다음과 같습니다.

 r=( $(grep gis aaa) )

시도해 보면 다음과 같은 내용이 즉시 표시됩니다.

 printf '<%s>\n' $(grep gis aaa)

"$IFS" 내의 문자(기본적으로 공백, 탭, 줄 바꿈)를 기준으로 분할됩니다.

그리고파일의 값을 와일드카드에 노출합니다. 그러면 몇 가지 *, ?[…](어떤 것은 비밀번호의 파일 목록과 몇 가지 쉘 옵션에 따라 달라집니다)이 변환됩니다.

한 가지(권장되지 않음) 해결책은 IFS분할 문자로 변경하는 것입니다.그리고분할을 비활성화하는 와일드카드:

 IFS=$'\n'; set -f; r=( $(grep gis aaa) )

그러나 더 간단한 해결책은 셸에서 이미 제공하는 기능을 사용하는 것입니다.

readarray -t r <(grep gis aaa) 

이는 개행 문자로 분할됩니다(경로 이름에 개행 문자가 없다고 가정).

그런 다음 줄을 공백 분할 및 와일드카드에 노출시킬 수 있는 각 부분을 얻기 위해 각 줄을 다시 분할하지 않도록 줄의 선행 및 후행 부분을 제거해 보겠습니다.

"/각 줄의 처음부터 (큰따옴표 및 슬래시)까지의 모든 항목과 "(큰따옴표 및 공백)부터 끝까지의 모든 항목을 제거하면 깨끗한 경로 이름을 얻을 수 있습니다.

 #!/bin/bash

 function nodatechk() {
    for l do
        l="/${l#*\"/}"                # Remove leading text up to `"/`
        l=${l%\" *}                   # Remove trailing text from `" `
        printf '%s\n' "$l"
    done
 }

 readarray -t r < <(grep gis aaa)

 nodatechk "${r[@]}"

답변2

유일한 grep해결책은

grep gis aaa | grep -o '^[^"]*"[^"]*"' | grep -o '"[^"]*"$'

첫 번째는 grep귀하의 질문에 있는 것과 동일합니다. 분명히 gis(행의 어느 곳이든)을 포함하는 행을 선택합니다 . 두 번째 grep,

grep -o '^[^"]*"[^"]*"'

행(예: 열 1~4)에서 첫 번째로 인용된 문자열을 포함하여 모든 항목과 일치합니다. 그리고, 이로 인해 -o 옵션, 출력오직그 말.  세 번째 grep,

grep -o '"[^"]*"$'

행(이 시점에서 원래 행의 열 4)에서 마지막으로 인용된 문자열과 일치하고 해당 문자열만 출력합니다.


PS 파일의 각 열 쌍 사이에 탭 문자가 있고 값에 탭 문자가 포함되어 있지 않은 경우 네 번째 열을 얻는 쉬운 방법은 다음과 같습니다.

awk -F'\t' '/gis/ { print $4 }' aaa

답변3

나는 읽었다이 게시물나는 "eval"을 사용하여 이 문제를 해결했습니다. 따라서 다음 줄을 변경했습니다.

r=( $(grep gis aaa) )

도착하다

eval r="( $(grep gis aaa) )"

관련 정보