STDOUT'un n'inci satırını alma komutu


210

STDOUT'un n'inci satırını almanızı sağlayacak herhangi bir bash komutu var mı?

Yani, bunu alacak bir şey

$ ls -l
-rw-r--r--@ 1 root  wheel my.txt
-rw-r--r--@ 1 root  wheel files.txt
-rw-r--r--@ 1 root  wheel here.txt

ve böyle bir şey yap

$ ls -l | magic-command 2
-rw-r--r--@ 1 root  wheel files.txt

Yeniden kullanılması gereken komut dosyaları yazarken bunun kötü bir uygulama olacağını anlıyorum, ancak kabukla her gün çalışırken STDOUT'umu böyle bir şekilde filtrelemenin benim için yararlı olacağını düşünüyorum.

Ayrıca, bu yazmak için yarı önemsiz bir komut olacağını fark (tampon STDOUT, belirli bir satır döndürmek), ama bunu yapmak için bir betiği yerine bırakmadan kullanılabilir bazı standart kabuk komutu olup olmadığını bilmek istiyorum .


5
Ben sadece bu kelimeyi kullanmak için oymagic-command
Sevenearths

Yanıtlar:


332

Kullanımı sedsadece çeşitli,:

ls -l | sed -n 2p

Gerekli satır yazdırıldığında girişi okumayı bıraktığından daha verimli görünen bu alternatifin kullanılması, besleme işleminde bir SIGPIPE oluşturabilir ve bu da istenmeyen bir hata mesajı oluşturabilir:

ls -l | sed -n -e '2{p;q}'

lsSIGPIPE aldığında şikayet eden bir komut olmasa da , genellikle ilkini kullandığım kadar sık ​​sık gördüm (ki bu daha kolay, yine de) .

Bir dizi çizgi için:

ls -l | sed -n 2,4p

Birkaç çizgi aralığı için:

ls -l | sed -n -e 2,4p -e 20,30p
ls -l | sed -n -e '2,4p;20,30p'

P ne anlama geliyor? 2p 3p gibi mi? Bunun 2/3 çizgisi için olduğunu anlıyorum, ama arkasındaki teori / anlayış nedir?
Leo Ufimtsev

4
@LeoUfimtsev: polan sedçizgilerin aralığı olduğunu ilerlettiği bunun tespit hatları yazdırır beyanı. Böylece 2,4pbaskı hatları 2, 3, 4 anlamına gelir.
Jonathan Leffler

3
Ve ndiğer tüm satırları
Timo

85
ls -l | head -2 | tail -1

13
+2, ama şunu öneririm head -n 2 | tail -n 1- modern başlıklar ve kuyruklar aksi takdirde uyarı verme eğilimindedir.
Michael Krelin - hacker

2
Verileri filtrelemek için iki işlem kullanmak biraz fazladır (ancak bugünlerde makinelerin gücü göz önüne alındığında, muhtemelen başa çıkacaklardı). Bir aralığı işlemek için head -n M | tail -n M-N+1genelleme tamamen önemsiz değildir (N..M aralığı için, kullanırsınız ) ve birden çok aralığı işlemek için genelleme yapmak mümkün değildir.
Jonathan Leffler

3
kafa kuyruk boru? korkunç. Bunu yapmanın birden iyi yolları.
camh

16
* Nix komut satırı hakkında harika bir şey: bir milyon ve her şeyi yapmanın bir yolu ve herkesin bir favorisi var ve diğer tüm yollardan nefret ediyor ... :-)
dilenciler

1
Satır aralığı başka bir yol yazdırmak için: $ ls -l | awk '{if (NR>=4 && NR<=64) print}'(... vb daha kolay fazla koşul, çoklu aralıkları ekleyebilir)
user10607

41

Güzel kafa / kuyruk yoluna alternatif:

ls -al | awk 'NR==2'

veya

ls -al | sed -n '2p'

1
benim awk daha iyi, ama sed güzel.
Michael Krelin - hacker

"İf" ye gerek yok - bilgisayar korsanının cevabına bakın ( sistemdeki her dosyayı bulma kısmı hariç ). ;-)
sonraki duyuruya kadar duraklatıldı.

ne anlama geliyor '2p'?
parçalama

1
@ parçalama kısa cevap baskı ikinci satır; long -> Kullanıldığında, yalnızca kalıpla eşleşen satırlara adresten sonra komut verilir. Kısaca, / p bayrağıyla kullanıldığında eşleşen satırlar iki kez yazdırılır: sed '/ PATTERN / p' dosyası. Ve elbette PATTERN daha
Medhat

ya 2bir değişkense? Her örnek tek tırnak kullanır, ancak bir var ile çift tırnak gerekir. Awk'yi vars kullanırken tek tırnaklarla da çalışacak şekilde "programlayabilir miyiz?" Örnek line =1; ls | awk 'NR==$line'. Ben bashvars ile çift tırnak kullanır biliyorum .
Timo

21

Gönderen sed1line :

# print line number 52
sed -n '52p'                 # method 1
sed '52!d'                   # method 2
sed '52q;d'                  # method 3, efficient on large files

Gönderen awk1line :

# print line number 52
awk 'NR==52'
awk 'NR==52 {print;exit}'          # more efficient on large files

9

Bütünlüğü uğruna ;-)

daha kısa kod

find / | awk NR==3

daha kısa ömür

find / | awk 'NR==3 {print $0; exit}'

Tamlık hakkında şaka yapmıyorsunuz!
sonraki duyuruya kadar duraklatıldı.

Ben değilim ;-) Aslında, herkesin neden kullandığını bilmiyorum ls- asıl soru birinin hakkındaydı STDOUT, bu yüzden daha büyük olmanın daha iyi olduğunu düşündüm.
Michael Krelin - hacker

En azından GNU awk ile varsayılan eylem { print $0 }, yani `awk 'NR == 3' aynı şeyi yazmanın daha kısa bir yoludur.
ephemient

Muhtemelen bu eyleme "; exit" eklemeniz gerekir. Onlarla hiçbir şey yapmayacağınız zaman çizgilerin geri kalanını işlemenin anlamı yok.
camh

@camh: Jonathan Leffer'ın şu konuda cevabına bakınız: "besleme sürecinde bir SIGPIPE oluşturabilir ve bu da istenmeyen bir hata mesajı verebilir".
ephemient


6

Awk kullanabilirsiniz:

ls -l | awk 'NR==2'

Güncelleme

Yukarıdaki kod, tek tek hata nedeniyle istediğimizi alamayacak: ls -l komutunun ilk satırı toplam satırdır. Bunun için aşağıdaki revize edilmiş kod çalışacaktır:

ls -l | awk 'NR==3'

4

Perl kolayca ulaşılabilir mi?

$ perl -n -e 'if ($. == 7) { print; exit(0); }'

Açıkçası 7 için istediğiniz sayıyı değiştirin.


Bu benim favorim çünkü kişisel olarak ne olduğumu genelleştirmek için en kolay gibi görünüyor, bu da her n., Perl -n -e 'if ($.% 7 == 0) {print; çıkış (0); } '
mat kelcey

@matkelcey ayrıca $ awk 'NR % 7' filenameher 7. satırı dosyaya yazdırabilirsiniz.
user10607

3

Başka bir poster önerdi

ls -l | head -2 | tail -1

ancak başınızı kuyruğa sokarsanız, N çizgisine kadar her şey iki kez işlenir gibi görünüyor.

Kuyruk kafasına borulama

ls -l | tail -n +2 | head -n1

daha verimli olur mu?


0

Evet, en etkili yol (Jonathan Leffler tarafından zaten belirtildiği gibi) sed'i print & quit ile kullanmaktır:

set -o pipefail                        # cf. help set
time -p ls -l | sed -n -e '2{p;q;}'    # only print the second line & quit (on Mac OS X)
echo "$?: ${PIPESTATUS[*]}"            # cf. man bash | less -p 'PIPESTATUS'

Pipefail ve PIPESTATUS kullanımı çok ilginç ve bu sayfaya çok şey katıyor.
Mike S

0

Hmm

sed benim durumumda işe yaramadı. Öneriyorum:

"tek" satırlar için 1,3,5,7 ... ls | awk '0 == (NR + 1)% 2'

"çift" satırlar için 2,4,6,8 ls | awk '0 == (NR)% 2'


-1

Daha fazla bütünlük için ..

ls -l | (for ((x=0;x<2;x++)) ; do read ; done ; head -n1)

İkinciye gelene kadar çizgileri atın, ardından ilk satırı yazdırın. Böylece, 3. satırı yazdırır.

Sadece ikinci satırsa ..

ls -l | (read; head -n1)

Gerektiği kadar çok 'okuma' koyun.


-1

Bunu .bash_profile dosyama ekledim

function gdf(){
  DELETE_FILE_PATH=$(git log --diff-filter=D --summary | grep delete | grep $1 | awk '{print $4}')
  SHA=$(git log --all -- $DELETE_FILE_PATH | grep commit | head -n 1 | awk '{print $2}')
  git show $SHA -- $DELETE_FILE_PATH
}

Ve işe yarıyor

gdf <file name>

Şaşkınım - bunun soru ile ne ilgisi var?
Jonathan Leffler
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.