web-dev-qa-db-ja.com

CSVファイルで値を検索して、それに関連付けられた別の値を取得するにはどうすればよいですか?

myfile.csv

445,aLabel
446,anotherLabel
447,aThirdLabel

Bashスクリプトで、myfile.csv内で(大文字と小文字を区別しない方法で)「anotherLabel」の存在を検索し、値446を取得します。さらに、「anotherLabel」が存在しない場合は追加します最後まで、前の行のトークンを1増やします。

ifステートメントから始めました:

if grep -Fiq anotherLabel myfile.csv; then
    #get the value of field 1 (446 in this example) and store it in a variable
else
    #increment the last value of field 1 present in the file and store it in a variable
    #and append "448,anotherLabel" to myfile.csv
fi

Grepを使用してラベルがファイル内にあるかどうかを確認することがこれに近づく最善の方法であるか、sedまたはawkを使用するより簡単な方法があるかどうかはわかりません。

2
mariahm24

これはあなたが必要とするものです:

$ awk -v tgt='the string you want to find' '
    BEGIN { FS=OFS="," }
    tolower($2) == tolower(tgt) { print $1 | "cat>&2"; f=1 }
    { print; p=$1 }
    END { if (!f) { print ++p, tgt; print p | "cat>&2"} exit !f }
' file

例えば:

$ var=$( { awk -v tgt='anotherLabel' 'BEGIN{FS=OFS=","} tolower($2) == tolower(tgt){print $1 | "cat>&2"; f=1} {print; p=$1} END {if (!f) { print ++p, tgt; print p | "cat>&2"} exit !f}' file > out1; } 2>&1 )
$ echo "exit status: $?, value found: $var"
exit status: 0, value found: 446
$ cat out1
445,aLabel
446,anotherLabel
447,aThirdLabel

$ var=$( { awk -v tgt='missingLabel' 'BEGIN{FS=OFS=","} tolower($2) == tolower(tgt){print $1 | "cat>&2"; f=1} {print; p=$1} END {if (!f) { print ++p, tgt; print p | "cat>&2"} exit !f}' file > out1; } 2>&1 )
$ echo "exit status: $?, value found: $var"
exit status: 1, value found: 448
$ cat out1
445,aLabel
446,anotherLabel
447,aThirdLabel
448,missingLabel

上記は、$ 2に一致するか、ファイルの最後にstderrに新しく追加された$ 1を出力し(変数「var」にキャプチャされます)、ターゲット文字列が見つかった場合は終了ステータスを成功に設定し、それ以外の場合は失敗に設定します、ファイル全体をstdoutに出力し、必要に応じて欠損値を追加します。

1
Ed Morton

これを試してください:

 awk -F',' '{ if ($2 == "anotherLabel") { print $1 } }' myfile.csv
1
Bart

次のawkコードは、あなたが求めるものを実行します:

_#!/bin/bash

filetosearch=myfile.csv
searchString=${1:-anotherLabel}

awk -F',' -v pat="$searchString" '
BEGIN{patl=tolower(pat);flag=0};
{prev=$1}(tolower($0)==patl){flag=1;exit}
END{
     if(flag){
          print prev
             }else{
          printf("%s%s%s\n", prev+1,FS,pat) >> ARGV[1]    # use ARGIND in gawk.
          print prev+1
             }
   }' "${filetosearch}"
_

完全な行に完全に一致する文字列_"${searchString}"_を検索し(tolower($0)==patltolower($0)~patlに変更して、より緩やかに一致させる)、それが見つかったインデックスを報告します。文字列が一致しない場合、ファイルの最後のインデックスより1つ多いインデックスで使用されるファイルに追加(追加)されます。

例:

_$ ./script aLabel
445

$ ./script anotherLabel
446

$ ./script MissingLabel
450

$ cat myfile.csv
445,aLabel
446,anotherLabel
447,aThirdLabel
448,dhdhdhdhdhd
449,anotherLabel4646
450,MissingLabel
_
1
Isaac

grepおよびtailの使用:

_search="anotherLabel"
file=myfile.csv

if value=$(grep -Pio -m1 "^[0-9]+(?=,$search$)" "$file"); then
    echo "do something with $value"
Elif lastvalue=$(tail -n1 "$file" | grep -o '^[0-9]\+'); then
    # append lastvalue + 1 and search string
    echo "$((++lastvalue)),$search" >> "$file"
else
    # handle error
    echo "error. no integer value in last line of \"$file\" found." >&2
fi
_

最初のgrepでは、次のオプションが使用されます。

  • _-P_ Perl互換の正規表現(PCRE)が正の先読みを使用できるようにします(以下を参照)。
  • _-i_パターンの大文字と小文字を区別しない
  • _-o_行の一致する部分のみを印刷します
  • _-m1_最初の一致後に停止

最初の正規表現^[0-9]+(?=,$search$)は、正の先読み_(?=pattern)_を使用して、その後に_,_が続く数値と、コンマなしの検索文字列および一致自体の一部である検索文字列を一致させます。オプション_-o_と組み合わせて、一致する部分(数値)のみが出力されます。

1
Freddy

純粋なbashでこれを実行したい場合:

file="myfile.csv"
seek="anotherLabel"
while IFS=, read id label; do
    if [[ $label == "$seek" ]]; then
        myid=$id
        break
    fi
    lastid=$id
done < "$file"
if [[ -z $myid ]]; then
    myid=$((lastid + 1))
    echo "$myid,$seek" >> "$file"
fi
echo "$seek id is: $myid"
1
glenn jackman

診断とエラー処理を省略した場合は、これを少し短くすることができます。

file="myfile.csv"
label="$1"
if [ "$label" != "" ]
then
        IFS="," read val1 val2 <<< "$(awk -F, -v look4="$label" \
                'tolower($2) == tolower(look4) { found=1; print $1 "," $2; }
                        END { if (!found) print $1; }' "$file")"
        if [ "$val2" != "" ]
        then
                echo "Found value $val1 with label $val2."
        else
                val1=$((val1+1))
                if printf "%s,%s\n" "$val1" "$label" >> "$file"
                then
                        echo "Added value $val1 to file for label $label."
                else
                        echo "Failed to add value $val1 to file."
                fi
        fi
else
        echo "Missing label."
        exit
fi

これは Bart’s answer に基づいており、awkを使用して各行の2番目のフィールド($2)を目的のラベルと比較しますが、テストでは大文字と小文字を区別しません。上記のコードの実行後、$var1には、$labelに対応する値が含まれます。 $var2が空白でない場合は、見つかったexactラベルが含まれています。 $var2が空白の場合、ラベルは見つかりませんでした(そして、ファイルに追加しようとしました)。

以下のスクリプトで終わりました

入力があるかどうか教えてください

count=`awk '{print NR}' o.txt| awk '{print NR}'|sed -n '$p'`

for ((i=1;i<=$count;i++)); do sed -n ''$i'p' o.txt| grep "anotherLabel">/dev/null; if [[ $? == 0 ]]; then echo "anotherlabel exists"; awk -F "," -v i="$i"  'NR==i && $2 == "anotherLabel" {print $1}' o.txt; uni_anotherlabel=`sed -n ''$i'p' o.txt| grep "anotherLabel"| awk -F "," '{print $1}'`;else echo "anotherlabel doesnt exsists"; echo "$uni_anotherlabel"; fi; done
0