Bir csv dosyam varsa, yalnızca tek bir sütunun içeriğini yazdırmanın hızlı bir bash yolu var mı? Her satırın aynı sayıda sütuna sahip olduğunu varsaymak güvenlidir, ancak her sütunun içeriği farklı uzunlukta olacaktır.
Bir csv dosyam varsa, yalnızca tek bir sütunun içeriğini yazdırmanın hızlı bir bash yolu var mı? Her satırın aynı sayıda sütuna sahip olduğunu varsaymak güvenlidir, ancak her sütunun içeriği farklı uzunlukta olacaktır.
Yanıtlar:
Bunun için awk kullanabilirsiniz. '$ 2'yi istediğiniz n'inci sütuna değiştirin.
awk -F "\"*,\"*" '{print $2}' textfile.csv
gawk -F"|" "{print $13}" files*.csv
...,"string,string",...
"
ve sonuncusu ile "
awk -F "\"*;\"*" '{print $2}' textfile.csv
Evet. cat mycsv.csv | cut -d ',' -f3
3. sütunu yazdıracaktır.
Bunu yapabilmemin en basit yolu sadece csvtool kullanmaktı . Csvtool'u kullanmak için başka kullanım durumlarım da vardı ve sütun verilerinin kendisinde görünürlerse tırnakları veya sınırlayıcıları uygun şekilde işleyebilir.
csvtool format '%(2)\n' input.csv
2'yi sütun numarasıyla değiştirmek, aradığınız sütun verilerini etkili bir şekilde çıkaracaktır.
cat input.csv | csvtool formath '%(2)\n' -
Not Burada cat'in işe yaramaz olduğunu biliyorum ama normalde bir csv'yi dışa aktaracak herhangi bir komut için kullanın.
format '%(2)\n'
komut bir alanın nerede bittiğini söyleyemez. (CsvTool 1.4.2)
csvtool
kullanmayı gerektiriyor gibi görünüyor -
.
csvtool format '%(1),%(10)\n' - < in.csv > out.csv
Sekmeyle ayrılmış bir dosyadan çıkarmak isteyen buraya indi. Ekleyeceğimi düşündüm.
cat textfile.tsv | cut -f2 -s
Burada -f2
2, sıfır olmayan endeksli sütun veya ikinci sütun ekstreleri.
cat
gereksiz:< textfile.tsv cut -f2 -s
Bu sorulara verilecek pek çok cevap harika ve hatta bazıları köşedeki vakalara baktı. Günlük kullanımda olabilen basit bir cevap eklemek istiyorum ... çoğunlukla bu köşedeki durumlara giriyorsunuz (tırnak içinde kaçan virgül veya virgül vb.).
FS (Alan Ayırıcı), değeri uzaya düşürülen değişkendir. Yani awk varsayılan olarak herhangi bir satır için boşlukta böler.
Yani BEGIN (Giriş almadan önce yürüt) kullanarak bu alanı istediğimiz herhangi bir şeye ayarlayabiliriz ...
awk 'BEGIN {FS = ","}; {print $3}'
Yukarıdaki kod 3. sütunu bir csv dosyasında yazdıracaktır.
Diğer yanıtlar iyi çalışıyor, ancak yalnızca bash kabuğunu kullanarak bir çözüm istediğinizden, bunu yapabilirsiniz:
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
Ve sonra şu şekilde sütunları (bu örnekte ilki) çekebilirsiniz:
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
Yani burada birkaç şey oluyor:
while IFS=,
- bu, kabuğun alanları (metin blokları) neyin ayırdığını bilmek için kullandığı IFS (Dahili Alan Ayırıcı) olarak virgül kullanmayı söylüyor. Yani IFS = demek, IFS = "" ise "a, b" nin "a b" ile aynı olduğunu söylemek gibidir (varsayılan olarak budur.)
read -a csv_line;
- bu, her satırda birer birer oku ve her öğenin "csv_line" olarak adlandırıldığı bir dizi oluşturup bunu while döngümüzün "do" bölümüne gönder diyor.
do echo "${csv_line[0]}";done < file
- şimdi "yap" aşamasındayız ve "csv_line" dizisinin 0. elemanını yankıla diyoruz. Bu işlem dosyanın her satırında tekrarlanır. < file
Bölüm sadece yerden okumaya while döngüsü anlatıyor. NOT: bash'de dizilerin 0 dizinli olduğunu unutmayın, bu nedenle ilk sütun 0. öğedir.
İşte burada, kabuktaki bir CSV'den bir sütun çıkarıyorsunuz. Diğer çözümler muhtemelen daha pratiktir, ancak bu tamamen bash.
GNU Awk'ı kullanabilirsiniz , kullanım kılavuzunun bu makalesine bakın . Makalede (Haziran 2015'te) sunulan çözümde bir iyileştirme olarak, aşağıdaki gawk komutu çift tırnaklı alanlar içinde çift tırnak kullanımına izin verir; çift tırnak, iki ardışık çift tırnak ("") ile işaretlenir. Dahası, bu boş alanlara izin verir, ancak bu bile çok satırlı alanları işleyemez . Aşağıdaki örnek c=3
, textfile.csv dosyasının 3. sütununu (aracılığıyla ) yazdırır :
#!/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)
Kullanımına dikkat dos2unix
"\ n" ve UTF-8, (bayt sırası işareti olmadan) sırasıyla mümkün DOS tarzı satır sonları dönüştürmek için (CRLF yani "\ r \ n") ve (bayt sırası işareti), UTF-16 kodlaması. Standart CSV dosyaları satır sonu olarak CRLF kullanır, Wikipedia'ya bakın .
Giriş çok satırlı alanlar içeriyorsa, aşağıdaki komut dosyasını kullanabilirsiniz. Çıktıda kayıtları ayırmak için özel dizge kullanımına dikkat edin (çünkü bir kayıt içinde varsayılan ayırıcı satırsonu olabilir). Yine, aşağıdaki örnek c=3
textfile.csv dosyasının 3. sütununu (üzerinden ) yazdırır :
#!/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)
Soruna başka bir yaklaşım var. csvquote , alandaki özel karakterlerin dönüştürülmesi için değiştirilmiş bir CSV dosyasının içeriğini çıkarabilir , böylece belirli bir sütunu seçmek için normal Unix metin işleme araçları kullanılabilir. Örneğin, aşağıdaki kod üçüncü sütunun çıktısını verir:
csvquote textfile.csv | cut -d ',' -f 3 | csvquote -u
csvquote
rastgele büyük dosyaları işlemek için kullanılabilir.
İşte 2 sütunlu bir csv dosyası örneği
myTooth.csv
Date,Tooth
2017-01-25,wisdom
2017-02-19,canine
2017-02-24,canine
2017-02-28,wisdom
İlk sütunu almak için şunu kullanın:
cut -d, -f1 myTooth.csv
f Alan anlamına gelir ve d sınırlayıcı anlamına gelir
Yukarıdaki komutu çalıştırmak aşağıdaki çıktıyı üretecektir.
Çıktı
Date
2017-01-25
2017-02-19
2017-02-24
2017-02-28
Yalnızca 2. sütunu almak için:
cut -d, -f2 myTooth.csv
Ve işte çıktı Çıktı
Tooth
wisdom
canine
canine
wisdom
incisor
Başka bir kullanım durumu:
Csv girdi dosyanız 10 sütun içeriyor ve 2'den 5'e kadar olan sütunları ve ayırıcı olarak virgül kullanarak 8'inci sütunları istiyorsunuz ".
cut, sütunları belirtmek için -f ("alanlar" anlamına gelir) ve ayırıcıyı belirtmek için -d ("sınırlayıcı" anlamına gelir) kullanır. İkincisini belirtmeniz gerekir çünkü bazı dosyalar sütunları ayırmak için boşluklar, sekmeler veya iki nokta üst üste kullanabilir.
cut -f 2-5,8 -d , myvalues.csv
cut bir komut yardımcı programıdır ve işte birkaç örnek daha:
SYNOPSIS
cut -b list [-n] [file ...]
cut -c list [file ...]
cut -f list [-d delim] [-s] [file ...]
Düzgün CSV ayrıştırma değil, gerekli cut
/ awk
ve dua. Bunu bir mac'ta deniyorum csvtool
, ancak mac'ler Ruby ile geliyor, yani şunları yapabilirsiniz:
echo "require 'csv'; CSV.read('new.csv').each {|data| puts data[34]}" | ruby
Önce temel bir CSV oluşturacağız
[dumb@one pts]$ cat > file
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
Sonra 1. sütunu alıyoruz
[dumb@one pts]$ awk -F , '{print $1}' file
a
1
a
1
Bence en kolayı csvkit kullanmak :
2. sütunu alır:
csvcut -c 2 file.csv
Bununla birlikte, csvtool ve muhtemelen bir dizi başka csv bash aracı da vardır:
sudo apt-get install csvtool
(Debian tabanlı sistemler için)
Bu, içinde 'ID' bulunan ilk satırın bulunduğu bir sütun döndürür.
csvtool namedcol ID csv_file.csv
Bu, dördüncü satırı döndürür:
csvtool col 4 csv_file.csv
Başlık satırını bırakmak isterseniz:
csvtool col 4 csv_file.csv | sed '1d'
Şimdiye kadarki cevapların hiçbirinde neden csvkit'ten bahsetmediğini merak ediyorum.
csvkit, CSV'ye dönüştürmek ve CSV ile çalışmak için bir komut satırı araçları paketidir
Ben sadece csv veri yönetimi için kullanıyorum ve şu ana kadar cvskit kullanarak çözemediğim bir problem bulamadım.
Bir cvs dosyasından bir veya daha fazla sütun çıkarmak csvcut
için araç kutusunun bir parçası olan yardımcı programı kullanabilirsiniz . İkinci sütunu çıkarmak için şu komutu kullanın:
csvcut -c 2 filename_in.csv > filename_out.csv
Csv'deki dizeler tırnak içine alınmışsa, q
seçenekle tırnak karakterini ekleyin :
csvcut -q '"' -c 2 filename_in.csv > filename_out.csv
pip install csvkit
Veya ile yükleyin sudo apt install csvkit
.
Tam bir CSV ayrıştırıcısı olmadan bunu yapamazsınız.
cut
?
Bu kodu bir süredir kullanıyorum, "stackoverflow'dan kesme ve yapıştırma" yı saymadığınız sürece "hızlı" değildir.
Bir döngüde IFS yerine $ {##} ve $ {%%} operatörlerini kullanır. 'Err' ve 'die' çağırır ve SEP karakterleri olarak yalnızca virgül, tire ve boruyu destekler (ihtiyacım olan tek şey bu).
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*}
}
Misal:
$ 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
echo '1,"2,3,4,5",6' | awk -F "\"*,\"*" '{print $2}'
2
yerine yazdıracak2,3,4,5
.