Csvファイルがある場合、単一の列のみの内容を印刷する簡単なbash方法はありますか?各行の列数は同じであると想定しても安全ですが、各列のコンテンツの長さは異なります。
これにはawkを使用できます。 '$ 2'を必要なn番目の列に変更します。
awk -F "\"*,\"*" '{print $2}' textfile.csv
はい。 cat mycsv.csv | cut -d ',' -f3
は3列目を出力します。
これを実現できる最も簡単な方法は、 csvtool を使用することです。 csvtoolを使用する他のユースケースもあり、列データ自体に引用符または区切り文字が含まれている場合、それらを適切に処理できます。
csvtool format '%(2)\n' input.csv
2を列番号に置き換えると、探している列データが効果的に抽出されます。
タブ区切りファイルから抽出するためにここに着陸しました。私が追加すると思いました。
cat textfile.tsv | cut -f2 -s
-f2
は、2の非ゼロインデックス列、または2番目の列を抽出します。
この質問に対する多くの回答は素晴らしいものであり、一部のケースではコーナーケースについても検討しています。私は日常的に使用できる簡単な答えを追加したいと思います...ほとんどの場合、それらの角の場合になります(エスケープされたコンマや引用符でのコンマなど)。
FS(フィールドセパレーター)は、値がスペースにフォールトされる変数です。そのため、awkはデフォルトで任意の行のスペースで分割します。
したがって、BEGIN(入力を取得する前に実行)を使用して、このフィールドを必要なものに設定できます...
awk 'BEGIN {FS = ","}; {print $3}'
上記のコードは、csvファイルの3列目を印刷します。
他の答えはうまくいきますが、bashシェルだけを使用して解決策を求めたので、これを行うことができます。
AirBoxOmega:~ d$ cat > file #First we'll create a basic CSV
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
そして、次のように列(この例の最初の列)を引き出すことができます。
AirBoxOmega:~ d$ while IFS=, read -a csv_line;do echo "${csv_line[0]}";done < file
a
1
a
1
a
1
a
1
a
1
a
1
そのため、ここでいくつかのことが行われています。
while IFS=,
-これは、フィールド(テキストのブロック)を区切るものを知るためにシェルが使用するIFS(Internal Field Separator)としてコンマを使用することを言っています。つまり、IFS =と言うことは、「a、b」は「a b」と同じようなことです。IFS= ""の場合(これはデフォルトです)
read -a csv_line;
-これは、各行を1つずつ読み取り、各要素が「csv_line」と呼ばれる配列を作成し、whileループの「do」セクションに送信することを意味します
do echo "${csv_line[0]}";done < file
-「do」フェーズにあり、配列「csv_line」の0番目の要素をエコーしていると言います。このアクションは、ファイルのすべての行で繰り返されます。 < file
部分は、whileループにどこから読み込むかを伝えるだけです。注:bashでは、配列のインデックスは0であるため、最初の列は0番目の要素です。
これで、シェルのCSVから列を引き出しました。他のソリューションはおそらくより実用的ですが、これは純粋なbashです。
GNU Awkを使用できます。 ユーザーガイドのこの記事 を参照してください。記事(2015年6月)で提示されたソリューションの改善として、次のgawkコマンドは二重引用符付きフィールド内の二重引用符を許可します。二重引用符は、2つの連続する二重引用符( "")でマークされます。さらに、これは空のフィールドを許可しますが、これでも複数行フィールドを処理できません。次の例では、textfile.csvの3番目の列(c=3
経由)を出力します。
#!/bin/bash
gawk -- '
BEGIN{
FPAT="([^,\"]*)|(\"((\"\")*[^\"]*)*\")"
}
{
if (substr($c, 1, 1) == "\"") {
$c = substr($c, 2, length($c) - 2) # Get the text within the two quotes
gsub("\"\"", "\"", $c) # Normalize double quotes
}
print $c
}
' c=3 < <(dos2unix <textfile.csv)
dos2unix
を使用して、可能性のあるDOSスタイルの改行(CRLFすなわち "\ r\n")およびUTF-16エンコーディング(バイトオーダーマーク付き)をそれぞれ "\ n"およびUTF-8(バイトオーダーマークなし)に変換することに注意してください。標準CSVファイルはCRLFを改行として使用します。 Wikipedia を参照してください。
入力に複数行のフィールドが含まれる場合は、次のスクリプトを使用できます。出力でレコードを分離するための特別な文字列の使用に注意してください(デフォルトの区切り改行はレコード内で発生する可能性があるため) 。繰り返しますが、次の例では、textfile.csvの3番目の列(c=3
経由)を出力します。
#!/bin/bash
gawk -- '
BEGIN{
RS="\0" # Read the whole input file as one record;
# assume there is no null character in input.
FS="" # Suppose this setting eases internal splitting work.
ORS="\n####\n" # Use a special output separator to show borders of a record.
}
{
nof=patsplit($0, a, /([^,"\n]*)|("(("")*[^"]*)*")/, seps)
field=0;
for (i=1; i<=nof; i++){
field++
if (field==c) {
if (substr(a[i], 1, 1) == "\"") {
a[i] = substr(a[i], 2, length(a[i]) - 2) # Get the text within
# the two quotes.
gsub(/""/, "\"", a[i]) # Normalize double quotes.
}
print a[i]
}
if (seps[i]!=",") field=0
}
}
' c=3 < <(dos2unix <textfile.csv)
問題に対する別のアプローチがあります。 csvquote は、通常のUnixテキスト処理ツールを使用して特定の列を選択できるように、フィールド内の特殊文字が変換されるように変更されたCSVファイルの内容を出力できます。たとえば、次のコードは3番目の列を出力します。
csvquote textfile.csv | cut -d ',' -f 3 | csvquote -u
csvquote
を使用して、任意の大きなファイルを処理できます。
[dumb @ one pts] $ cat> file#最初に基本的なCSVを作成します
a、b、c、d、e、f、g、h、i、k
1,2,3,4,5,6,7,8,9,10
a、b、c、d、e、f、g、h、i、k
1,2,3,4,5,6,7,8,9,10
[dumb @ one pts] $ awk -F、 '{print $ 1}'ファイル
a
1
a
1
cut
/awk
と祈りではなく、適切なCSV解析が必要でした。 csvtool
のないMacでこれを試していますが、MacにはRubyが付属しているので、次のことができます。
echo "require 'csv'; CSV.read('new.csv').each {|data| puts data[34]}" | Ruby
完全なCSVパーサーなしでは実行できません。
csvtool col 2 file.csv
ここで、2は興味のある列です
あなたもできる
csvtool col 1,2 file.csv
複数の列を行う
これまでのところ、csvkitについての回答がなかったのはなぜですか。
csvkitは、CSVに変換して操作するためのコマンドラインツールのスイートです。
私はそれをcsvデータ管理専用に使用していますが、今のところcvskitを使用して解決できない問題は見つかりませんでした。
Cvsファイルから1つ以上の列を抽出するには、ツールボックスの一部であるcsvcut
ユーティリティを使用できます。 2番目の列を抽出するには、次のコマンドを使用します。
csvcut -c 2 filename_in.csv > filename_out.csv
Csvの文字列が引用符で囲まれている場合は、q
オプションを使用して引用文字を追加します。
csvcut -q '"' -c 2 filename_in.csv > filename_out.csv
pip install csvkit
またはSudo apt install csvkit
を使用してインストールします。
最も簡単なのは csvkit を使用することだと思います:
2番目の列を取得します:csvcut -c 2 file.csv
ただし、 csvtool もあり、おそらく他にも多くのcsv bashツールがあります:
Sudo apt-get install csvtool
(Debianベースのシステム用)
これにより、最初の行に「ID」が含まれる列が返されます。 csvtool namedcol ID csv_file.csv
これは4番目の行を返します:csvtool col 4 csv_file.csv
ヘッダー行をドロップする場合:
csvtool col 4 csv_file.csv | sed '1d'
これは2列のcsvファイルの例です
myTooth.csv
Date,Tooth
2017-01-25,wisdom
2017-02-19,canine
2017-02-24,canine
2017-02-28,wisdom
最初の列を取得するには、次を使用します。
cut -d, -f1 myTooth.csv
fはフィールドを表し、dは区切り文字を表します
上記のコマンドを実行すると、次の出力が生成されます。
出力
Date
2017-01-25
2017-02-19
2017-02-24
2017-02-28
2列目のみを取得するには:
cut -d, -f2 myTooth.csv
そして、ここに出力がありますOutput
Tooth
wisdom
canine
canine
wisdom
incisor
別のユースケース:
Csv入力ファイルには10個の列が含まれており、カンマを区切り文字として使用して、列2〜5および列8が必要です。
cutは、-f(「フィールド」を意味する)を使用して列を指定し、-d(「デリミター」を意味する)を使用して区切り文字を指定します。一部のファイルでは列を区切るためにスペース、タブ、またはコロンを使用する場合があるため、後者を指定する必要があります。
cut -f 2-5,8 -d , myvalues.csv
cutはコマンドユーティリティであり、ここにいくつかの例を示します。
SYNOPSIS
cut -b list [-n] [file ...]
cut -c list [file ...]
cut -f list [-d delim] [-s] [file ...]
しばらくこのコードを使用していましたが、「stackoverflowからのカットアンドペースト」をカウントしない限り、「クイック」ではありません。
IFSの代わりにループで$ {##}および$ {%%}演算子を使用します。 'err'と 'die'を呼び出し、SEP charsとしてコンマ、ダッシュ、およびパイプのみをサポートします(必要なのはこれだけです)。
err() { echo "${0##*/}: Error:" "$@" >&2; }
die() { err "$@"; exit 1; }
# Return Nth field in a csv string, fields numbered starting with 1
csv_fldN() { fldN , "$1" "$2"; }
# Return Nth field in string of fields separated
# by SEP, fields numbered starting with 1
fldN() {
local me="fldN: "
local sep="$1"
local fldnum="$2"
local vals="$3"
case "$sep" in
-|,|\|) ;;
*) die "$me: arg1 sep: unsupported separator '$sep'" ;;
esac
case "$fldnum" in
[0-9]*) [ "$fldnum" -gt 0 ] || { err "$me: arg2 fldnum=$fldnum must be number greater or equal to 0."; return 1; } ;;
*) { err "$me: arg2 fldnum=$fldnum must be number"; return 1;} ;;
esac
[ -z "$vals" ] && err "$me: missing arg2 vals: list of '$sep' separated values" && return 1
fldnum=$(($fldnum - 1))
while [ $fldnum -gt 0 ] ; do
vals="${vals#*$sep}"
fldnum=$(($fldnum - 1))
done
echo ${vals%%$sep*}
}
例:
$ CSVLINE="example,fields with whitespace,field3"
$ $ for fno in $(seq 3); do echo field$fno: $(csv_fldN $fno "$CSVLINE"); done
field1: example
field2: fields with whitespace
field3: field3
Whileループも使用できます
IFS=,
while read name val; do
echo "............................"
echo Name: "$name"
done<itemlst.csv