要素にスペースがある 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[@]}"

3行目(および5行目)に二重引用符が含まれていても、要素にスペースがあるため、出力が壊れていました。

この問題をどのように解決できますか? (ところで、awkまたはcutを使用して列を印刷できることを知っていますが、この場合はgrepを使用したいと思います。)ありがとう。

答え1

問題の根本原因は次のとおりです。

 r=( $(grep gis aaa) )

試してみると、次の内容がすぐに表示されます。

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

「$IFS」内の文字(デフォルトでは空白、タブ、改行)に基づいて分割されます。

そしてファイルの値をワイルドカードに公開します。これにより、いくつかの*?および[…](いくつかはパスワードのファイルのリストといくつかのシェルオプションに依存します)が変換されます。

1つの(推奨されていない)解決策は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(行のどこにでも)を含む行を選択します。 2番目のgrep、

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

行(たとえば、列1〜4)で最初に引用された文字列を含むすべての項目と一致します。 そして、これにより -o オプション、出力ただその言葉。  3番目のgrep、

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

行(この時点で元の行の列4)で最後に引用された文字列と一致し、その文字列のみを出力します。


PSファイルの各列ペアの間にタブ文字があり、値にタブ文字が含まれていない場合は、4番目の列を取得する簡単な方法は次のとおりです。

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

答え3

私は読んだこの投稿私は "eval"を使ってこの問題を解決しました。したがって、次の行を変更しました。

r=( $(grep gis aaa) )

到着

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

関連情報