Satırları ve sütunları aktarma


18

Aşağıdaki gibi bir dosya var.

title1:A1
title2:A2
title3:A3
title4:A4
title5:A5

title1:B1
title2:B2
title3:B3
title4:B4
title5:B5

title1:C1
title2:C2
title3:C3
title4:C4
title5:C5

title1:D1
title2:D2
title3:D3
title4:D4
title5:D5

Bunu nasıl başarabilirim?

title1    title2     title3    title4
A1         A2         A3         A4
B1         B2         B3         B4
C1         C2         C3         C4
D1         D2         D3         D4


lütfen lütfen awk kullanmayın, perl veya python veya gerçek bir programlama dili ile özel bir çözüm de kullanabilirsiniz veya istediğinizi elde etmek için birden fazla geçişle tr / cut kullanabilirsiniz
Rudolf Olah

Yanıtlar:



9

Komut satırından sütunlarla satırları dönüştürmek için özel bir çözümün dışında, bunu yapabildiğimi gördüğüm tek şey ironik olarak adlandırılan bir araçtır transpose.

Kurulum

Ne yazık ki herhangi bir depoda değil, bu yüzden indirmeniz ve derlemeniz gerekecek. Bağımlı olduğu ek bir kütüphanesi olmadığı için bu oldukça basittir. Bu şekilde gerçekleştirilebilir:

$ gcc transpose.c -o transpose

kullanım

Basit metin dosyalarını kolaylıkla işleyebilir. Örneğin:

$ cat simple.txt 
X column1 column2 column3
row1 0 1 2
row2 3 4 5
row3 6 7 8
row4 9 10 11

Bu komut kullanılarak aktarılabilir:

$ transpose -t --fsep " " simple.txt 
X row1 row2 row3 row4
column1 0 3 6 9
column2 1 4 7 10
column3 2 5 8 11

Bu komut transposetranspose ( -t) işlevidir ve kullanılacak alan ayırıcı bir boşluktur ( --fsep " ").

Örneğiniz

Örnek verileriniz biraz daha karmaşık bir formatta olduğundan, 2 aşamada ele alınması gerekir. İlk önce transposebaşa çıkabilecek bir biçime çevirmemiz gerekiyor.

Bu komutu çalıştırmak, verileri daha yatay bir biçimde oluşturur:

$ sed 's/:/ /; /^$/d' sample.txt \
    | sort | paste - - - - -
title1 A1   title1 B1   title1 C1   title1 D1   title2 A2
title2 B2   title2 C2   title2 D2   title3 A3   title3 B3
title3 C3   title3 D3   title4 A4   title4 B4   title4 C4
title4 D4   title5 A5   title5 B5   title5 C5   title5 D5

Şimdi sadece title1, title2, vb. İkincil oluşumlarını kaldırmamız gerekiyor:

$ sed 's/:/ /; /^$/d' sample.txt \
    | sort | paste - - - - - | sed 's/\ttitle[0-9] / /g'
title1 A1 B1 C1 D1 A2
title2 B2 C2 D2 A3 B3
title3 C3 D3 A4 B4 C4
title4 D4 A5 B5 C5 D5

Şimdi transposebaşa çıkabilecek bir formatta . Aşağıdaki komut, transpozisyonun tamamını yapar:

$ sed 's/:/ /; /^$/d' sample.txt \
    | sort | paste - - - - - | sed 's/\ttitle[0-9] / /g' \
    | transpose -t --fsep " "
title1 title2 title3 title4
A1 B2 C3 D4
B1 C2 D3 A5
C1 D2 A4 B5
D1 A3 B4 C5
A2 B3 C4 D5

8

Kullanabilirsin awk sonra verileri işlemek için pasteve columnbiçimlendirmek için.

Sanırım burada title1 , yalnızca yayınınızda bir örnek olduğunu ve bu verilerin :başlık + verileri arasında ayırıcı hariç olmadığını .

nkaç sütun yazdırılacağını belirtir (kesik çizgilerle eşleşmelidir paste).

awk -F":" -v n=4 \
'BEGIN { x=1; c=0;} 
 ++c <= n && x == 1 {print $1; buf = buf $2 "\n";
     if(c == n) {x = 2; printf buf} next;}
 !/./{c=0;next}
 c <=n {printf "%s\n", $2}' datafile | \
 paste - - - - | \
 column -t -s "$(printf "\t")"

Daha esnek ve bakımı kolay yapmak istiyorsanız, komut dosyası olarak yazabilirsiniz. İşte bash sarıcı kullanan bir örnekawk ve buna bağlanancolumn . Bu şekilde, örneğin başlıkların tüm satırlarda doğru olduğundan emin olmak gibi daha fazla veri denetimi yapabilirsiniz.

Genellikle şu şekilde kullanılır:

$ ./trans -f data -c 4
title one  title two  title three  title four
A1         A2         A3           A4
B1         B2         B3           B4
C1         C2         C3           C4
D1         D2         D3           D4

Üstbilgiler her zaman daha kısaysa, veriler de üstbilgi genişliklerini kaydedebilir ve ardından printfbirlikte %-*satlayabilirsiniz column.

#!/bin/bash

trans()
{
    awk -F":" -v ncol="$1" '
    BEGIN {
        level = 1 # Run-level.
        col   = 1 # Current column.
        short = 0 # If requested to many columns.
    }
    # Save headers and data for row one.
    level == 1 {
        head[col] = $1
        data[col] = $2
        if (++col > ncol) { # We have number of requested columns.
            level = 2
        } else if ($0 == "") { # If request for more columns then available.
            level = 2
            ncol  = col - 2
            short = 1
        } else {
            next
        }
    }
    # Print headers and row one.
    level == 2 {
        for (i = 1; i <= ncol; ++i)
            printf("%s\t", head[i])
        print ""
        for (i = 1; i <= ncol; ++i)
            printf("%s\t", data[i])
        level = 3
        col = ncol + 1
        if (!short)
            next
    }
    # Empty line, new row.
    ! /./ { print ""; col = 1; next }
    # Next cell.
    col > ncol {next}
    {
        printf "%s%s", $2, (col <= ncol) ? "\t" : ""
        ++col
    }
    END {print ""}
    ' "$2"
}

declare -i ncol=4  # Columns defaults to four.
file=""            # Data file (or pipe).

while [[ -n "$1" ]]; do
    case "$1" in
    "-c") ncol="$2"; shift;;
    "-f") file="$2"; shift;;
    *) printf "Usage: %s [-c <columns>] [-f <file> | pipe]\n" \
        "$(basename $0)" >&2;
        exit;;
    esac
    shift
done

trans "$ncol" "$file" | column -t -s "$(printf "\t")"

1
Güzel cevap! @JoelDavis ve ben bunu hackledik, ama cevabınız müthiş!
slm

7

İşte dosyayı istediğiniz formata koymanın hızlı bir yolu:

$ grep -Ev "^$|title5" sample.txt | sed 's/title[0-9]://g' | paste - - - -
A1  A2  A3  A4
B1  B2  B3  B4
C1  C2  C3  C4
D1  D2  D3  D4

Sütun başlıklarını istiyorsanız:

$ grep -Ev "^$|title5" sample.txt | sed 's/:.*//' | sort -u | tr '\n' '\t'; \
    echo ""; \
    grep -Ev "^$|title5" a | sed 's/title[0-9]://g' | paste - - - -
title1  title2  title3  title4  
A1      A2      A3      A4
B1      B2      B3      B4
C1      C2      C3      C4
D1      D2      D3      D4

2. komut nasıl çalışır?

afiş yazdırma
grep -Ev "^$|title5" sample.txt | sed 's/:.*//' | sort -u | tr '\n' '\t';
pankarttan sonra iade koymak
echo
veri satırlarını yazdırma
grep -Ev "^$|title5" a | sed 's/title[0-9]://g' | paste - - - -

Yapıştır komutu basitçe işimi yaptı. cevap için teşekkürler ...
SK Venkat


3

Muhtemelen bunu formüle etmenin daha kısa bir yolu var, ancak bu genel etkiyi başarıyor gibi görünüyor:

[jadavis84@localhost ~]$ sed 's/^title[2-9]://g' file.txt | tr '\n' '\t' | sed 's/title1:/\n/g' ; echo

A1  A2  A3  A4  A5      
B1  B2  B3  B4  B5      
C1  C2  C3  C4  C5      
D1  D2  D3  D4  D5  
[jadavis84@localhost ~]$ 

çoklu sed çağırma doğru gelmiyor (ve sed'in yeni satır çevirisini de yapabileceğinden eminim) bu yüzden muhtemelen bunu yapmanın en basit yolu değil. Ayrıca, bu başlıkların üstünü keser, ancak satırlar / alanlar düzgün biçimlendirildikten sonra bunları manuel olarak oluşturabilirsiniz.

Daha iyi bir yanıt, muhtemelen bu etkiyi sadece kullanmaya sedveya awkyapmaya indirgeyecek, böylece bir seferde sadece bir şeyin olması gerekir. Ama yoruldum, bu yüzden bir araya getirebildim.


Joel - Aynı hatayı yaptım ve fark ettim, çıktıda title5 sütununu istemiyor.
slm

Ah, sonunda awk iyi koşmak bunu düzeltmek gerekir. Ama görünüşe göre Sukminder tam bir çözüm gönderdi.
Bratchley

1

pastemuhtemelen en iyi seçeneğinizdir. Sen ile ilgili bitleri çıkarabilir cut, grepve awkbu gibi:

(awk 'NR==1' RS= infile | cut -d: -f1; cut -sd: -f2 infile)

5. sütunun kaldırılması gerekiyorsa şu şekilde ekleyin awk 'NR%5':

(awk 'NR==1' RS= infile | cut -d: -f1; cut -sd: -f2 infile) | awk 'NR%5'

Şimdi şununla sütun oluştur paste:

(awk 'NR==1' RS= infile | cut -d: -f1; cut -sd: -f2 infile) | awk 'NR%5' | paste - - - -

Çıktı:

title1  title2  title3  title4
A1  A2  A3  A4
B1  B2  B3  B4
C1  C2  C3  C4
D1  D2  D3  D4

0

Sadece devrik kısım için, son zamanlarda benzer bir sorun yaşadım ve kullandım:

awk -v fmt='\t%4s'  '{ for(i=1;i<=NF;i++){ a[i]=a[i] sprintf(fmt, $i); } } END { for (i in a) print a[i]; }'

Fmt değerini gerektiği gibi ayarlayın. Her girdi satırı için, her alanı bir dizi öğesine birleştirir. Awk string birleşiminin örtük olduğunu unutmayın: herhangi bir işleç olmadan iki şey yazdığınızda olur.

Örnek G / Ç:

i       mark    accep   igna    utaal   bta
-22     -10     -10     -20     -10     -10
-21     -10     -10     -20     -10     -10
-20     -10     -10     -20     -10     -10
-19     -10     0       -10     -10     -10
-18     0       0       -10     0       0
-12     0       0       -10     0       0
-11     0       0       -10     0       0
-10     0       0       -10     0       0

çıktı:

       i     -22     -21     -20     -19     -18     -12     -11     -10
    mark     -10     -10     -10     -10       0       0       0       0
    accep    -10     -10     -10       0       0       0       0       0
    igna     -20     -20     -20     -10     -10     -10     -10     -10
    utaal    -10     -10     -10     -10       0       0       0       0
     bta     -10     -10     -10     -10       0       0       0       0

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.