sıralama ancak üstbilgi satırını üstte tut


55

Önce bir grup sütun başlığı olan bir satır, sonra da bir grup veri üreten bir programdan çıktı alıyorum. Bu çıktının çeşitli sütunlarını kesmek ve çeşitli sütunlara göre sıralanmış olarak görüntülemek istiyorum. Başlıklar olmadan, kesme ve sıralama, sütunların bir alt kümesini birlikte görüntüleme veya görüntüleme -kseçeneği ile kolayca gerçekleştirilir . Ancak, bu sıralama yöntemi, sütun başlıklarını çıktı satırlarının geri kalanıyla karıştırır. Başlıkları üstte tutmanın kolay bir yolu var mı?sortcutawk


1
Aşağıdaki linke rastladım . Ancak, bu { head -1; sort; }çalışma tekniğini alamıyorum . İlk satırdan sonra daima bir demet metni siler. Bunun neden olduğunu bilen var mı?
jonderry

1
Sanırım bunun nedeni headbirden fazla satırı bir ara belleğe okuyup çoğunu atmak. Benim sedfikrim de aynı problemdi.
Andy

@ jonderry - bu teknik sadece lseekgirdiyle çalışır, böylece bir borudan okurken işe yaramaz. Bir dosyaya yönlendirirseniz >outfileve sonra çalıştırırsanız çalışır{ head -n 1; sort; } <outfile
don_crissti 26:15

Yanıtlar:


58

Andy'nin fikrini çalmak ve onu bir işlev haline getirmek, böylece kullanımı daha kolay:

# print the header (the first line of input)
# and then run the specified command on the body (the rest of the input)
# use it in a pipeline, e.g. ps | body grep somepattern
body() {
    IFS= read -r header
    printf '%s\n' "$header"
    "$@"
}

Şimdi yapabilirim:

$ ps -o pid,comm | body sort -k2
  PID COMMAND
24759 bash
31276 bash
31032 less
31177 less
31020 man
31167 man
...

$ ps -o pid,comm | body grep less
  PID COMMAND
31032 less
31177 less

ps -C COMMANDdaha uygun olabilir grep COMMAND, ama bu sadece bir örnek. Ayrıca, -Cbaşka bir seçim seçeneği de kullandıysanız kullanamazsınız -U.
Mikel

Veya belki de aranmalı body? Olduğu gibi body sortya body grep. Düşünceler?
Mikel

3
Dan yeniden adlandırıldı headeriçin bodybeden harekete yapıyoruz çünkü. Umarım bu daha mantıklı.
Mikel

2
bodyDaha sonraki tüm boru hattı katılımcılarını aramayı unutmayın :ps -o pid,comm | body grep less | body sort -k1nr
bishop 20

1
@Tim Sadece <foo body sort -k2veya yazabilirsiniz body sort -k2 <foo. İstediğiniz şeyden sadece bir ekstra karakter.
Mikel

36

Başlığı şöyle bash ile üstte tutabilirsiniz:

command | (read -r; printf "%s\n" "$REPLY"; sort)

Veya perl ile yapın:

command | perl -e 'print scalar (<>); print sort { ... } <>'

2
+1 harika. Sanırım bir kabuk işlevi olarak toplanmaya değer.
Mikel

1
+1, alt kabuğun tercih edilmesinin herhangi bir nedeni veya {}yerine tamam ()mı?
jonderry

2
IFS=girişi okurken sözcük bölmeyi devre dışı bırakır. Okurken gerekli olduğunu sanmıyorum $REPLY. ayarlanırsa echoters eğik çizgi kaçar xpg_echo(varsayılan değil). printfbu durumda daha güvenlidir. echo $REPLYtırnak işaretleri olmadan boşlukları yoğunlaştıracak; Bence iyi echo "$REPLY"olmalı. read -rgiriş ters eğik çizgi kaçışları içeriyorsa gereklidir. Bunlardan bazıları bash versiyonuna bağlı olabilir.
Andy

1
@Andy: Vay, haklısın, read REPLY; echo $REPLY(önde gelen boşlukları sorar ) ve read; echo $REPLY(değil) için farklı kurallar vardır .
Mikel

1
@Andy: IIRC, varsayılan değer xpg_echosisteminize bağlıdır, örneğin Solaris'te varsayılanın doğru olduğunu düşünüyorum. Bu yüzden Gilles printfbu kadar çok şey seviyor : Tahmin edilebilir davranışa sahip tek şey bu.
Mikel

23

Komut dosyalarında güzel çalışan bir awk sürümü buldum :

awk 'NR == 1; NR > 1 {print $0 | "sort -n"}'

1
Bu hoşuma gitti, ama biraz açıklama gerektiriyor - boru awk betiğinin içinde. Bu nasıl çalışıyor? sortKomutu dışarıdan mı çağırıyor ? Hiç kimse awk içindeki boru kullanımını açıklayan bir sayfanın bağlantısını biliyor mu?
Wildcard

@Wildcard resmi manuel sayfa veya bu astarı kontrol edebilirsiniz .
lapo,

4

Etkili ama etkili: sıralamadan önce 0tüm başlık satırlarına ve 1tüm diğer satırlara hazırlanın. Sıralamadan sonra ilk karakteri soyun.

… |
awk '{print (NR <= 2 ? "0 " : "1 ") $0}' |
sort -k 1 -k… |
cut -b 3-

3

İşte her şeyi sıralamak için çıktılarınızı yönlendirebileceğiniz, ancak ilk sırayı en üstte tutabilen sihirli perl hattı gürültüsü: perl -e 'print scalar <>, sort <>;'


2

command | {head -1; sort; }Çözümü denedim ve işleri gerçekten berbat ettiğini doğrulayabiliyorum - headborudan çoklu satırlarda okuyor, sonra sadece birincisini çıkarıyor. Çıktı, geri kalanı Yani head vermedi okumak, geçirilen sorthat 2'den başlayan çıkışın geri kalanını --NOT!

Sonuç hatları (ve bir kısmi çizgi) komut çıktısının başında olduğumuzu eksik olduğunu (eğer hala ilk çizgi var hariç) - bir boru ekleyerek onaylamak için kolay bir gerçektir wcsonunda Yukarıdaki boru hattı - ama bunu bilmiyorsanız izini sürmek son derece zordur! Çözümü yapmadan önce çıktıımda neden kısmi bir çizgi (ilk 100 bayt ya da öylesine kesilmiş) olduğunu çözmek için en az 20 dakika harcadım.

Yaptığım, güzel işleyen ve komutu iki kez çalıştırmayı gerektirmeyen bir şeydi:

myfile=$(mktemp)
whatever command you want to run > $myfile

head -1 $myfile
sed 1d $myfile | sort

rm $myfile

Çıktıyı bir dosyaya koymanız gerekirse, şunu değiştirebilirsiniz:

myfile=$(mktemp)
whatever command you want to run > $myfile

head -1 $myfile > outputfile
sed 1d $myfile | sort >> outputfile

rm $myfile

Sen ksh93 en kullanabilirsiniz headyerleşik veya line(hala birine sahip sistemlerde) yardımcı programını veya gnu-sed -u qveya IFS=read -r line; printf '%s\n' "$line"önlemek için bir kerede girdi bir bayt okuma.
Stéphane Chazelas

1

Bunun en kolay olduğunu düşünüyorum.

ps -ef | ( head -n 1 ; sort )

veya bu bir alt kabuk yaratmadığı için muhtemelen daha hızlıdır

ps -ef | { head -n 1 ; sort ; }

Diğer serin kullanımlar

Üstbilgi satırından sonra satırları karışık

cat file.txt |  ( head -n 1 ; shuf )

başlık satırından sonra satırları ters çevir

cat file.txt |  ( head -n 1 ; tac )

2
Bakınız unix.stackexchange.com/questions/11856/… . Bu aslında iyi bir çözüm değil.
Wildcard

1
Çalışmıyor, cat file | { head -n 1 ; sort ; } > file2sadece kafa göster
Peter Krauss

0
command | head -1; command | tail -n +2 | sort

4
Bu commandiki kez başlar . Bu nedenle bazı belirli komutlarla sınırlıdır. Ancak, psörnekte istenen komut için işe yarar.
jofel

0

Basit ve anlaşılır!

<command> | head -n 1; <command> | sed 1d | sort <....>
  • sed nd ---> 'n' satır numarasını belirtir ve 'd' silme anlamına gelir.

1
Nasıl jofel Sarva'nın cevabına bir buçuk yıl önce yorum yaptığında, bu commandiki kez başlar . Yani bir boru hattında kullanım için gerçekten uygun değil.
Wildcard

0

Buraya komut için bir çözüm aramaya geldim w. Bu komut kimin giriş yaptığını ve ne yaptığını gösterir.

Sıralanan sonuçları göstermek için, ancak üstte tutulan başlıklar varken (2 satır başlık var):

w | head -n 2; w | tail -n +3 | sort

Açıkçası bu komutu wiki kez çalıştırıyor ve bu nedenle tüm durumlar için uygun olmayabilir. Bununla birlikte, avantajına göre hatırlaması oldukça kolaydır.

Not tail -n +3demektir 'şov itibaren 3. ve bütün satırlar' (bkz man taildetaylar için).


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.