1

手入力ファイルを使用していますが、解析に問題があります。私のファイル入力ファイルは変更できず、私のコードの言語は bash スクリプトから変更できません。

わかりやすいように例を作ってみました^^

var="hey","i'm","happy, like","you"
IFS="," read -r one two tree for five <<<"$var"
echo $one:$two:$tree:$for:$five

ここで、すでに問題を見たと思います。私は取得したいです

hey:i'm:happy, like:you:

しかし、私は得る

hey:i'm:happy: like:you

read「 」が IFS よりも重要であることを に伝える方法が必要です。コマンドについて読みましたevalが、そのリスクを冒すことはできません。

最後にこれはディレクトリ ファイルであり、面倒なフィールドは説明フィールドなので、基本的に何でも入る可能性があります。

そのように見える元のファイル

"type","cn","uid","gid","gecos","description","timestamp","disabled"
"type","cn","uid","gid","gecos","description","timestamp","disabled"
"type","cn","uid","gid","gecos","description","timestamp","disabled"

編集#1

もっと良い例を挙げましょう。上記で使用したものは単純すぎて、@StefanHegny が別のエラーを引き起こすことがわかりました。

while read -r ldapLine
    do
            IFS=',' read -r objectClass dumy1 uidNumber gidNumber username description modifyTimestamp nsAccountLock gecos homeDirectory loginShell createTimestamp dumy2 <<<"$ldapLine"

            isANetuser=0

            while IFS=":" read -r -a class
            do
                    for i in "${class[@]}"
                    do
                            if [ "$i" == "account" ]
                            then
                                    isANetuser=1
                                    break
                            fi
                    done
            done <<< $objectClass

            if [ $isANetuser == 0 ]
            then
                    continue
            fi

            #MORE STUFF APPEND#

    done < file.csv

これはコードのごく一部ですが、私が何をしているのかを説明する必要があります。次のfile.csvような行がたくさんあります。

"top:shadowAccount:account:posixAccount","Jdupon","12345","6789","Jdupon","Jean Mark, Dupon","20140511083750Z","","Jean Mark, Dupon","/home/user/Jdupon","/bin/ksh","20120512083750Z","",""
4

2 に答える 2

2

使用するさまざまなbashバージョンがすべて、正規表現と導入された v3.0 よりも新しい場合はBASH_REMATCH、次の関数のようなものを使用できます。[注 1]

each_field () {
    local v=,$1;
    while [[ $v =~ ^,(([^\",]*)|\"[^\"]*\") ]]; do
        printf "%s\n" "${BASH_REMATCH[2]:-${BASH_REMATCH[1]:1:-1}}";
        v=${v:${#BASH_REMATCH[0]}};
    done
}

引数は 1 行 (引用することを忘れないでください!) であり、カンマ区切りの各フィールドを別の行に出力します。書かれているように、改行で囲まれたフィールドがないことを前提としています。これは CSV では合法ですが、ファイルを複数の行に分割することがより複雑になります。実際にそのシナリオに対処する必要がある場合は\n、printf ステートメントの を a に変更し、次の\0ようなものを使用xargs -0して出力を処理できます。printf(または、ステートメントの代わりに、必要な処理をフィールドに挿入することもできます。)

引用符で囲まれていないフィールドを変更せずに、引用符で囲まれたフィールドの引用符を外すと、問題が発生します。ただし、二重引用符が埋め込まれたフィールドでは失敗します。必要に応じて修正可能です。【注2】

これが明らかでない場合のサンプルを次に示します。

while IFS= read -r line; do
  each_field "$line"
  printf "%s\n" "-----"
done <<EOF
type,cn,uid,gid,gecos,"description",timestamp,disabled
"top:shadowAccount:account:posixAccount","Jdupon","12345","6789","Jdupon","Jean Mark, Dupon","20140511083750Z","","Jean Mark, Dupon","/home/user/Jdupon","/bin/ksh","20120512083750Z","",""

EOF

出力:

type
cn
uid
gid
gecos
description
timestamp
disabled
-----
top:shadowAccount:account:posixAccount
Jdupon
12345
6789
Jdupon
Jean Mark, Dupon
20140511083750Z

Jean Mark, Dupon
/home/user/Jdupon
/bin/ksh
20120512083750Z


-----

ノート:

  1. この機能を使うべきだと言っているのではありません。CSV パーサー、または Python などの優れた CSV 解析ライブラリを含む言語を使用する必要があります。しかし、この bash 関数は、特定の一般的な CSV 方言の正しくフォーマットされた CSV ファイルでは、ゆっくりではあるが機能すると思います。

  2. これは、引用符で囲まれたフィールド内の二重引用符を処理するバージョンです。これは、内部引用符の古典的な CSV 構文です。

    each_field () { 
        local v=,$1;
        while [[ $v =~ ^,(([^\",]*)|\"(([^\"]|\"\")*)\") ]]; do
            echo "${BASH_REMATCH[2]:-${BASH_REMATCH[3]//\"\"/\"}}";
            v=${v:${#BASH_REMATCH[0]}};
        done
    }
    
于 2016-05-25T15:15:45.863 に答える