it-swarm-tr.com

sütunları kullanarak metin dosyalarını birleştir

İki metin dosyam var. İlki içerik içeriyor:

Languages
Recursively enumerable
Regular

ikincisi içeriğe sahipken:

Minimal automaton
Turing machine
Finite

Onları sütun-bilge ile tek bir dosyada birleştirmek istiyorum. Ben de denedim paste 1 2 ve çıktısı:

Languages   Minimal automaton
Recursively enumerable  Turing machine
Regular Finite

Ancak sütunlar gibi iyi hizalanmış olmasını istiyorum

Languages               Minimal automaton
Recursively enumerable  Turing machine
Regular                 Finite

Elle idare etmeden bunu başarmanın mümkün olup olmadığını merak ediyordum.


Katma:

Bruce metodunun neredeyse çivi çaktığı başka bir örnek, neden merak ettiğim küçük bir yanlış hizalama hariç?

$ cat 1
Chomsky hierarchy
Type-0
—

$ cat 2
Grammars
Unrestricted

$ paste 1 2 | pr -t -e20
Chomsky hierarchy   Grammars
Type-0              Unrestricted
—                    (no common name)
54
Tim

Sadece column komutuna ihtiyacınız var ve sütunları ayırmak için sekmeleri kullanmasını söyleyin

paste file1 file2 | column -s $'\t' -t

"Boş hücre" tartışmalarına hitap etmek için sadece -ncolumn seçeneği:

$ paste <(echo foo; echo; echo barbarbar) <(seq 3) | column -s $'\t' -t
foo        1
2
barbarbar  3

$ paste <(echo foo; echo; echo barbarbar) <(seq 3) | column -s $'\t' -tn
foo        1
           2
barbarbar  3

Sütun kılavuz sayfam -n bir "Debian GNU/Linux uzantısıdır." Fedora sistemim boş hücre sorunu göstermiyor: BSD'den türetilmiş gibi görünüyor ve kılavuz sayfasında "Sürüm 2.23, -s seçeneğini açgözlü olmayacak şekilde değiştirildi" yazıyor

71
glenn jackman

Kullanışlı dandy pr komutunu arıyorsunuz:

paste file1 file2 | pr -t -e24

"-E24" "sekme duraklarını 24 aralığa genişlet" dir. Neyse ki, paste sütunlar arasına bir sekme karakteri koyar, böylece pr onu genişletebilir. "Yinelemeli numaralandırılabilir" karakterleri sayarak ve 2 ekleyerek 24'ü seçtim.

12
Bruce Ediger

Güncelleme: Burada çizelge çıktısı için çok daha basit bir script (sorunun sonundaki). Sadece paste için yaptığınız gibi dosya adını iletin ... Çerçeveyi yapmak için html kullanır, bu yüzden tweakable. Birden çok boşluğu korur ve unicode karakterlerle karşılaştığında sütun hizalaması korunur. Ancak, editör veya görüntüleyicinin unicode'u oluşturma biçimi tamamen başka bir konudur ...

┌──────────────────────┬────────────────┬──────────┬────────────────────────────┐
│ Languages            │ Minimal        │ Chomsky  │ Unrestricted               │
├──────────────────────┼────────────────┼──────────┼────────────────────────────┤
│ Recursive            │ Turing machine │ Finite   │     space indented         │
├──────────────────────┼────────────────┼──────────┼────────────────────────────┤
│ Regular              │ Grammars       │          │ ➀ unicode may render oddly │
├──────────────────────┼────────────────┼──────────┼────────────────────────────┤
│ 1 2  3   4    spaces │                │ Symbol-& │ but the column count is ok │
├──────────────────────┼────────────────┼──────────┼────────────────────────────┤
│                      │                │          │ Context                    │
└──────────────────────┴────────────────┴──────────┴────────────────────────────┘

#!/bin/bash
{ echo -e "<html>\n<table border=1 cellpadding=0 cellspacing=0>"
  paste "[email protected]" |sed -re 's#(.*)#\x09\1\x09#' -e 's#\x09# </pre></td>\n<td><pre> #g' -e 's#^ </pre></td>#<tr>#' -e 's#\n<td><pre> $#\n</tr>#'
  echo -e "</table>\n</html>"
} |w3m -dump -T 'text/html'

---

Cevaplar (şimdiye kadar) sunulan araçlar bir özeti.
Onlara oldukça yakından baktım; İşte buldum:

paste # Bu araç şimdiye kadar sunulan tüm cevaplar için ortaktır # Birden fazla dosyayı işleyebilir; bu nedenle birden çok sütun ... İyi! # Her sütunu bir Sekme ile sınırlandırır ... İyi. # Çıktıları tablo halinde verilmemiştir.

Aşağıdaki tüm araçlar bu sınırlayıcıyı kaldırır! ... Bir sınırlayıcıya ihtiyacınız varsa kötü.

column # Tab sınırlayıcısını kaldırır, bu nedenle alan tanımlaması tamamen iyi işlediği sütunlar tarafından yapılır .. Korkunç bir şey fark etmedim ... # Benzersiz bir sınırlayıcıya sahip olmanın yanı sıra, işe yarıyor ince!

expand # Yalnızca tek bir sekme ayarı var, bu nedenle 2 sütunun ötesinde tahmin edilemez # Unicode işlenirken sütunların hizalanması doğru değildir ve Sekme sınırlayıcıyı kaldırır, bu nedenle alan tanımlaması yalnızca sütun hizalaması ile yapılır

pr # Yalnızca tek bir sekme ayarı olduğundan, 2 sütunun ötesinde tahmin edilemez. # Unicode işlenirken sütunların hizalanması doğru değildir ve Sekme sınırlayıcıyı kaldırır, böylece alan tanımlaması yalnızca sütun hizalaması ile yapılır

Bana göre, column tek satırlık en iyi çözüm bu. Ya sınırlayıcı, ya da dosyalarınızın ASCII-art tablolaması olsun, aksi halde okuyun .. columns oldukça iyi dar :): ...


İşte herhangi bir sayıdaki dosyayı alan ve ASCII-art tablolu bir sunum oluşturan bir komut dosyasıdır. (Unicode'un beklenen genişliğe ulaşamayacağını unutmayın, örn. Tek bir karakter olan ௵. Bu, sütundan oldukça farklıdır. numaralar yanlıştır, yukarıda belirtilen bazı yardımcı programlarda olduğu gibi.) ... Komut dosyasının çıktısı, aşağıda gösterilen, F1 F2 F3 F4 adlı 4 giriş dosyasından ...

+------------------------+-------------------+-------------------+--------------+
| Languages              | Minimal automaton | Chomsky hierarchy | Grammars     |
| Recursively enumerable | Turing machine    | Type-0            | Unrestricted |
| Regular                | Finite            | —                 |              |
| Alphabet               |                   | Symbol            |              |
|                        |                   |                   | Context      |
+------------------------+-------------------+-------------------+--------------+

#!/bin/bash

# Note: The next line is for testing purposes only!
set F1 F2 F3 F4 # Simulate commandline filename args $1 $2 etc...

p=' '                                # The pad character
# Get line and column stats
cc=${#@}; lmax=                      # Count of columns (== input files)
for c in $(seq 1 $cc) ;do            # Filenames from the commandline 
  F[$c]="${!c}"        
  wc=($(wc -l -L <${F[$c]}))         # File length and width of longest line 
  l[$c]=${wc[0]}                     # File length  (per file)
  L[$c]=${wc[1]}                     # Longest line (per file) 
  ((lmax<${l[$c]})) && lmax=${l[$c]} # Length of longest file
done
# Determine line-count deficits  of shorter files
for c in $(seq 1 $cc) ;do  
  ((${l[$c]}<lmax)) && D[$c]=$((lmax-${l[$c]})) || D[$c]=0 
done
# Build '\n' strings to cater for short-file deficits
for c in $(seq 1 $cc) ;do
  for n in $(seq 1 ${D[$c]}) ;do
    N[$c]=${N[$c]}$'\n'
  done
done
# Build the command to suit the number of input files
source=$(mktemp)
>"$source" echo 'paste \'
for c in $(seq 1 $cc) ;do
    ((${L[$c]}==0)) && e="x" || e=":a -e \"s/^.{0,$((${L[$c]}-1))}$/&$p/;ta\""
    >>"$source" echo '<(sed -re '"$e"' <(cat "${F['$c']}"; echo -n "${N['$c']}")) \'
done
# include the ASCII-art Table framework
>>"$source" echo ' | sed  -e "s/.*/| & |/" -e "s/\t/ | /g" \'   # Add vertical frame lines
>>"$source" echo ' | sed -re "1 {h;s/[^|]/-/g;s/\|/+/g;p;g}" \' # Add top and botom frame lines 
>>"$source" echo '        -e "$ {p;s/[^|]/-/g;s/\|/+/g}"'
>>"$source" echo  
# Run the code
source "$source"
rm     "$source"
exit

İşte orijinal cevabım (yukarıdaki komut dosyasının yerine biraz kırpılmış)

Sütun genişliğini almak için wc ve bir visible karakteri . İle sağ tuşa sed kullanarak .. (sadece bu örnek için) .. . ve ardından paste ile iki sütuna a Sekme char ...

paste <(sed -re :a -e 's/^.{1,'"$(($(wc -L <F1)-1))"'}$/&./;ta' F1) F2

# output (No trailing whitespace)
Languages.............  Minimal automaton
Recursively enumerable  Turing machine
Regular...............  Finite

Doğru sütunu doldurmak istiyorsanız:

paste <( sed -re :a -e 's/^.{1,'"$(($(wc -L <F1)-1))"'}$/&./;ta' F1 ) \
      <( sed -re :a -e 's/^.{1,'"$(($(wc -L <F2)-1))"'}$/&./;ta' F2 )  

# output (With trailing whitespace)
Languages.............  Minimal automaton
Recursively enumerable  Turing machine...
Regular...............  Finite...........
9
Peter.O

Neredeyse bitti. paste her sütun arasına bir sekme karakteri koyar, böylece tek yapmanız gereken sekmeleri genişletmektir. (Dosyalarınızın sekme içermediğini varsayıyorum.) Sol sütunun genişliğini belirlemeniz gerekiyor. (Yeterince yeni) GNU yardımcı programları ile wc -L En uzun satırın uzunluğunu gösterir. Diğer sistemlerde awk ile ilk geçişi yapın. +1 sütunlar arasında istediğiniz boş alan miktarı.

paste left.txt right.txt | expand -t $(($(wc -L <left.txt) + 1))
paste left.txt right.txt | expand -t $(awk 'n<length {n=length} END {print n+1}')

BSD sütun yardımcı programınız varsa, sütun genişliğini belirlemek ve sekmeleri tek seferde genişletmek için kullanabilirsiniz. ( Değişmez bir sekme karakteridir; bash/ksh/zsh altında bunun yerine $'\t' Kullanabilirsiniz ve herhangi bir Kabuk'ta "$(printf '\t')" kullanabilirsiniz.)

paste left.txt right.txt | column -s '␉' -t

Bu çok aşamalı, bu yüzden optimal değil, ama işte gidiyor.

1) file1.txt.

while read line
do
echo ${#line}
done < file1.txt | sort -n | tail -1

Örneğin, en uzun çizgi 22'dir.

2) Pad'i kullanmak için awk kullanın file1.txt, printf ifadesiyle her satırı 22 karaktere kadar 22 karakterden az doldurma.

awk 'FS="---" {printf "%-22s\n", $1}' < file1.txt > file1-pad.txt

Not: FS için, file1.txt.

3) Daha önce yaptığınız gibi macunu kullanın.

$ paste file1-pad.txt file2.txt
Languages               Minimal automaton
Recursively enumerable  Turing machine
Regular                 Finite

Bu sık sık yaptığınız bir şeyse, bu kolayca bir komut dosyasına dönüştürülebilir.

4
bahamat

Glenn Jackman'ın cevabı hakkında yorum yapamıyorum, bu yüzden Peter.O'nun kaydettiği boş hücreler sorununu çözmek için bunu ekliyorum. Her sekmeden önce bir boş karakter eklenmesi, tek bir kesme olarak ele alınan ayırıcıların çalışmalarını ortadan kaldırır ve sorunu giderir. (Başlangıçta boşluk kullandım, ancak boş karakter karakterinin kullanılması sütunlar arasındaki fazla boşluğu ortadan kaldırır.)

paste file1 file2 | sed 's/\t/\0\t/g' | column -s $'\t' -t

Boş karakter çeşitli nedenlerle sorunlara neden oluyorsa, şunlardan birini deneyin:

paste file1 file2 | sed 's/\t/ \t/g' | column -s $'\t' -t

veya

paste file1 file2 | sed $'s/\t/ \t/g' | column -s $'\t' -t

Hem sed hem de column, Unix/Linux'un, özellikle BSD (ve Mac OS X) ve GNU/Linux'un lezzetleri ve sürümleri arasında uygulamada farklılık gösteriyor gibi görünüyor.

4
techno

bahamat’ın cevabı : Bu tamamen awk içinde yapılabilir, dosyaları sadece bir kez okur ve geçici dosyalar oluşturmaz. Sorunu belirtildiği gibi çözmek için

awk '
        NR==FNR { if (length > max_length) max_length = length
                  max_FNR = FNR
                  save[FNR] = $0
                  next
                }
                { printf "%-*s", max_length+2, save[FNR]
                  print
                }
        END     { if (FNR < max_FNR) {
                        for (i=FNR+1; i <= max_FNR; i++) print save[i]
                  }
                }
    '   file1 file2

Bu ilkin birçok awk komut dosyasında olduğu gibi, yukarıdaki ilk önce file1 'İ okur, save dizisindeki tüm verileri kaydeder ve aynı anda maksimum satır uzunluğunu hesaplar. Ardından file2 Değerini okur ve kaydedilmiş (file1) Verileri geçerli (file2) Verilerle yan yana yazdırır. Son olarak, file1file2 'Dan (daha fazla satır varsa) daha uzunsa, file1' Un son birkaç satırını (ikinci satırında karşılık gelen satır bulunmayan satırları) yazdırırız kolonu).

printf biçimiyle ilgili olarak:

  • "%-nns", nn karakter genişliğinde sola yaslanmış bir dize yazdırır.
  • "%-*s", nn Aynı şeyi yapar - * Bir sonraki parametreden alan genişliğini almasını söyler.
  • nn için maxlength+2 Kullanarak sütunlar arasında iki boşluk var. Açıkçası +2 ayarlanabilir.

Yukarıdaki komut dosyası yalnızca iki dosya için çalışır. Üç dosyayı veya dört dosyayı vb. İşlemek için önemsiz bir şekilde değiştirilebilir, ancak bu sıkıcı olacaktır ve bir egzersiz olarak bırakılmıştır. Ancak, işlemek için değiştirmek zor değildir herhangi bir sayı / dosya:

awk '
        FNR==1  { file_num++ }
                { if (length > max_length[file_num]) max_length[file_num] = length
                  max_FNR[file_num] = FNR
                  save[file_num,FNR] = $0
                }
        END     { for (j=1; j<=file_num; j++) {
                        if (max_FNR[j] > global_max_FNR) global_max_FNR = max_FNR[j]
                  }
                  for (i=1; i<=global_max_FNR; i++) {
                        for (j=1; j<file_num; j++) printf "%-*s", max_length[j]+2, save[j,i]
                        print save[file_num,i]
                  }
                }
    '   file*

Bu ilk betiğime çok benziyor, ancak

  • max_length Dizisine dönüşür.
  • max_FNR Dizisine dönüşür.
  • save öğesini iki boyutlu bir diziye dönüştürür.
  • all dosyaları kaydeder, all içeriği kaydeder. Daha sonra allEND bloğundan çıktı yazar.