Biorąc pod uwagę taki plik
First,Last,Age
Cory,Klein,27
John Jacob,Smith,30
Czy istnieje narzędzie wiersza polecenia do transponowania zawartości, aby dane wyjściowe wyglądały tak
First,Cory,John Jacob
Last,Klein,Smith
Age,27,30
Biorąc pod uwagę taki plik
First,Last,Age
Cory,Klein,27
John Jacob,Smith,30
Czy istnieje narzędzie wiersza polecenia do transponowania zawartości, aby dane wyjściowe wyglądały tak
First,Cory,John Jacob
Last,Klein,Smith
Age,27,30
Odpowiedzi:
ruby -rcsv -e 'puts CSV.parse(STDIN).transpose.map &:to_csv' < in.csv > out.csv
Analiza składni CSV nie jest łatwa do wykonania tylko za pomocą narzędzi POSIX, chyba że używasz uproszczonego wariantu CSV bez cudzysłowu (aby przecinki nie pojawiały się w polu). Nawet wtedy to zadanie nie wydaje się łatwe do wykonania z awk lub innym przetwarzaniem tekstu w narzędziu. Możesz używać Perla z Text::CSV
, Pythona z csv
, R z read.csv
, Ruby z CSV ,… (Wszystkie są częścią standardowej biblioteki odpowiedniego języka z wyjątkiem Perla.)
Na przykład w Pythonie:
import csv, sys
rows = list(csv.reader(sys.stdin))
writer = csv.writer(sys.stdout)
for col in xrange(0, len(rows[0])):
writer.writerow([row[col] for row in rows])
$ apt-get install csvtool
A następnie przekonwertować
$ csvtool transpose input.csv > ouput.csv
Lub w przygotowaniu
$ ... | csvtool transpose - | ...
... | csvtranspose | ...
to tylko pod względem składniowym.
Szybkie i brudne rozwiązanie bash :
c=1
file=file.txt
num_lines=$(wc -l < "$file")
for ((i=0; i<num_lines; i++)) {
cut -d, -f$c "$file" | paste -sd ','
((c++))
}
for ((i=1; i<=$num_cols; ++i)); do paste -s -d, <(cut -f$i -d, file.txt); done
this "is" example
komórka jest zakodowana "this ""is"" example"
Nie jestem przekonany, czy to rozwiązanie odpowiednio obsługuje takie przypadki
Biorąc pod uwagę sugerowane ograniczenie (bez cudzysłowu, bez osadzonych przecinków), jest on prosty w awk (tak jak w perlu, nie biorąc pod uwagę ponad tysiąca linii w CSV.pm
, 2300 linii w csv.rb
- python ma tylko 450 linii w csv.py
).
Oto przykład awk:
#!/usr/bin/awk -f
BEGIN { width=0; }
{
max = split($0, list, ",");
# printf "%d:%s\n", NR, $0;
if (width < max)
width = max;
for (n = 1; n <= max; ++n) {
sub("^[ ]*","",list[n]);
sub("[ ]*$","",list[n]);
# printf "\t%d:%s\n", n, list[n];
if ( columns[n] != "" ) {
columns[n] = columns[n] ", ";
}
columns[n] = columns[n] list[n];
}
}
END {
# printf "%d columns\n", width;
for (n = 1; n <= width; ++n) {
printf "%s\n", columns[n];
}
}
Nawiasem mówiąc: podany przykład miał dodatkową przestrzeń, która, jak zakładano, zostanie usunięta; inne przykłady nie dotyczyły tego szczegółu.
python
, b)ruby
jest nie mniej przenośna niżpython
, i c) pokazuje także, jak przekazać wejście / wyjście akta. Bravo @luikore, witamy w systemach Unix i Linux. Proszę, trzymaj się.