Perintah untuk mendapatkan baris ke-STDOUT


210

Apakah ada perintah bash yang memungkinkan Anda mendapatkan baris ke-10 dari STDOUT?

Artinya, sesuatu yang akan mengambil ini

$ 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

dan melakukan sesuatu seperti

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

Saya menyadari ini akan menjadi praktik yang buruk ketika menulis skrip yang dimaksudkan untuk digunakan kembali, TETAPI ketika bekerja dengan shell setiap hari itu akan berguna bagi saya untuk dapat menyaring STDOUT saya sedemikian rupa.

Saya juga menyadari ini akan menjadi perintah semi-sepele untuk menulis (buffer STDOUT, mengembalikan baris tertentu), tetapi saya ingin tahu apakah ada beberapa perintah shell standar untuk melakukan ini yang akan tersedia tanpa saya meletakkan skrip pada tempatnya.


5
Saya baru saja memilih ini untuk penggunaan katamagic-command
Sevenearths

Jawaban:


332

Menggunakan sed, hanya untuk variasi:

ls -l | sed -n 2p

Menggunakan alternatif ini, yang terlihat lebih efisien karena berhenti membaca input ketika baris yang diperlukan dicetak, dapat menghasilkan SIGPIPE dalam proses pengumpanan, yang pada gilirannya dapat menghasilkan pesan kesalahan yang tidak diinginkan:

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

Saya telah melihat bahwa cukup sering bahwa saya biasanya menggunakan yang pertama (yang lebih mudah untuk mengetik, toh), meskipun lsbukan perintah yang mengeluh ketika mendapat SIGPIPE.

Untuk rentang garis:

ls -l | sed -n 2,4p

Untuk beberapa rentang garis:

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

Apa arti p? seperti 2p 3p? Dalam arti saya mengerti bahwa ini untuk 2/3 baris, tapi apa teori / pemahaman di baliknya?
Leo Ufimtsev

4
@LeoUfimtsev: padalah sedpernyataan yang mencetak garis yang diidentifikasi oleh rentang garis yang mendahuluinya. Dengan demikian 2,4pberarti mencetak baris 2, 3, 4.
Jonathan Leffler

3
Dan nberarti TIDAK mencetak semua baris lainnya
Timo

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

13
+2, tapi saya sarankan head -n 2 | tail -n 1- kepala dan ekor modern cenderung mengeluarkan peringatan sebaliknya.
Michael Krelin - hacker

2
Menggunakan dua proses untuk memfilter data sedikit berlebihan (tetapi, mengingat kekuatan mesin saat ini, mereka mungkin akan mengatasinya). Generalisasi untuk menangani satu rentang tidak sepenuhnya sepele (untuk rentang N...M, Anda menggunakan head -n M | tail -n M-N+1), dan generalisasi untuk menangani beberapa rentang tidak dimungkinkan.
Jonathan Leffler

3
kepala disalurkan menjadi ekor? mengerikan. Banyak cara yang lebih baik untuk melakukannya.
camh

16
Hebat tentang * nix command line: satu juta dan satu cara untuk melakukan segalanya dan semua orang punya favorit dan membenci semua cara lain ... :-)
beggs

1
Cara mencetak berbagai baris dengan cara lain: $ ls -l | awk '{if (NR>=4 && NR<=64) print}'(dapat menambahkan lebih banyak kondisi lebih mudah, beberapa rentang, dll ...)
user10607

41

Alternatif cara kepala / ekor yang bagus:

ls -al | awk 'NR==2'

atau

ls -al | sed -n '2p'

1
awk saya lebih baik, tetapi sed bagus.
Michael Krelin - hacker

Tidak perlu "jika" - lihat jawaban peretas (kecuali untuk bagian tentang menemukan setiap file pada sistem). ;-)
Dijeda hingga pemberitahuan lebih lanjut.

apa artinya '2p'?
merobek

1
@shredding jawaban singkat cetak baris kedua; long -> Saat digunakan, hanya garis yang cocok dengan pola yang diberikan perintah setelah alamat. Secara singkat, ketika digunakan dengan flag / p, garis yang cocok dicetak dua kali: file sed '/ POLA / p'. Dan tentu saja POLA adalah ekspresi reguler yang lebih
Medhat

bagaimana jika 2suatu variabel? Setiap contoh menggunakan tanda kutip tunggal, tetapi dengan var Anda perlu tanda kutip ganda. Bisakah kita "memprogram" awk untuk bekerja juga dengan tanda kutip tunggal ketika menggunakan vars? Contoh line =1; ls | awk 'NR==$line'. Saya tahu itu bashmenggunakan tanda kutip ganda dengan vars.
Timo

21

Dari sed1line :

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

Dari awk1line :

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

9

Demi kelengkapan ;-)

kode yang lebih pendek

find / | awk NR==3

hidup yang lebih pendek

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

Anda tidak bercanda tentang kelengkapan!
Dijeda sampai pemberitahuan lebih lanjut.

Saya bukan ;-) Sebenarnya, saya tidak tahu mengapa semua orang menggunakan ls- pertanyaan asli adalah tentang seseorang STDOUT, jadi saya pikir lebih baik untuk membuatnya lebih besar.
Michael Krelin - hacker

Setidaknya dengan GNU awk, tindakan standarnya adalah { print $0 }, jadi `awk 'NR == 3' adalah cara yang lebih pendek untuk menulis yang sama.
ephemient

Anda mungkin harus menambahkan "; keluar" ke tindakan itu. Tidak ada gunanya memproses sisa baris ketika Anda tidak akan melakukan apa pun dengan mereka.
camh

@camh: Lihat jawaban Jonathan Leffer tentang itu: "dapat menghasilkan SIGPIPE dalam proses pemberian makan, yang pada gilirannya dapat menghasilkan pesan kesalahan yang tidak diinginkan".
ephemient


6

Anda dapat menggunakan awk:

ls -l | awk 'NR==2'

Memperbarui

Kode di atas tidak akan mendapatkan apa yang kita inginkan karena kesalahan satu per satu: baris pertama perintah ls-l adalah baris total . Untuk itu, kode revisi berikut akan berfungsi:

ls -l | awk 'NR==3'

4

Apakah Perl mudah tersedia untuk Anda?

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

Jelas mengganti nomor apa pun yang Anda inginkan untuk 7.


Ini adalah favorit saya karena tampaknya menjadi yang paling mudah untuk digeneralisasi dengan apa yang saya pribadi setelah setiap tanggal , perl -n -e 'if ($.% 7 == 0) {print; keluar (0); ''
mat kelcey

@matkelcey juga dapat Anda lakukan $ awk 'NR % 7' filenameuntuk mencetak setiap baris ke-7 dalam file.
user10607

3

Poster lain menyarankan

ls -l | head -2 | tail -1

tetapi jika Anda kepala pipa menjadi ekor, sepertinya semuanya hingga garis N diproses dua kali.

Pipa ekor ke kepala

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

akan lebih efisien?


0

Ya, cara paling efisien (seperti yang telah ditunjukkan oleh Jonathan Leffler) adalah menggunakan sed dengan print & berhenti:

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'

Penggunaan pipefail dan PIPESTATUS sangat menarik dan ini menambah banyak halaman ini.
Mike S

0

Hmm

sed tidak bekerja dalam kasus saya. Saya melamar:

untuk baris "ganjil" 1,3,5,7 ... ls | awk '0 == (NR + 1)% 2'

untuk "datar" baris 2,4,6,8 ls | awk '0 == (NR)% 2'


-1

Untuk kelengkapan lebih lanjut ..

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

Buang garis sampai Anda mendapatkan yang kedua, lalu cetak baris pertama setelah itu. Jadi, ia mencetak baris ke-3.

Jika itu hanya baris kedua ..

ls -l | (read; head -n1)

Letakkan sebanyak mungkin bacaan yang diperlukan.


-1

Saya menambahkan ini di .bash_profile saya

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
}

Dan itu berhasil

gdf <file name>

Saya bingung - apa hubungannya dengan pertanyaan ini?
Jonathan Leffler
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.