Bagaimana saya bisa menonton baris ke-17 (atau terakhir, jika kurang) dalam suatu folder?

8

Saya sedang menggunakan

watch head -n 17 *

yang bekerja, tetapi juga menunjukkan semua lini hingga tanggal 17. Pada dasarnya, saya hanya ingin menunjukkan baris terakhir untuk setiap file yang ditunjukkan dengan pendekatan saya saat ini. Bagaimana saya bisa mencapainya?

Contoh

Sebagai contoh, mari kita kurangi baris nr. ke 7. Jadi:

File contoh:

1
2
3
4
5
6
7
8

garis ini:

watch head -n 7 *

output

1
2
3
4
5
6
7

di mana saya ingin:

7
Felix Dombek
sumber

Jawaban:

15

Dengan GNU awk:

watch -x gawk '
  FNR == 17 {nextfile}
  ENDFILE   {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}' ./*

Yang memberikan output seperti:

        ./file1[17] line17
  ./short-file2[05] line 5 is the last

Perhatikan bahwa ./*gumpalan diperluas hanya sekali pada saat watchdipanggil.

Anda watch head -n 17 *adalah kerentanan perintah injeksi sewenang-wenang sebagai perluasan yang *benar-benar ditafsirkan sebagai kode shell oleh shell yang watchmemanggil untuk menafsirkan gabungan dari argumen dengan spasi.

Jika ada file yang dipanggil $(reboot)di direktori saat ini, itu akan reboot.

Dengan -x, kami meminta watchuntuk melewati shell dan menjalankan perintah secara langsung. Atau, Anda bisa melakukan:

watch 'exec gawk '\''
  FNR == 17 {nextfile}
  ENDFILE   {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}'\'' ./*'

Untuk watchmenjalankan shell yang akan memperluas ./*glob di setiap iterasi. watch foo barberlaku sama dengan watch -x sh -c 'foo bar'. Saat menggunakan watch -x, Anda dapat menentukan shell mana yang Anda inginkan dan misalnya memilih yang lebih kuat seperti zshitu dapat melakukan globbing rekursif dan membatasi ke file biasa:

watch -x zsh -c 'awk '\''...'\'' ./**/*(.)'

Tanpa gawk, Anda masih bisa melakukan sesuatu seperti:

watch '
  for file in ./*; do
    [ -s "$file" ] || continue
    printf "%s: " "$file"
    head -n 17 < "$file" | tail -n 1
  done'

Memberikan ouput seperti:

./file1: line17
./short-file2: line 5 is the last

Tapi itu akan menjadi jauh lebih efisien karena ini berarti menjalankan beberapa perintah per file.

Stéphane Chazelas
sumber
Terima kasih atas catatan keamanannya. Sebenarnya Anda benar dan perintah saya juga tidak melakukan apa yang saya butuhkan, yaitu menonton file yang ditambahkan, yang juga diselesaikan versi Anda. Satu-satunya downside adalah bahwa saya perlu belajar AWK, saya punya meskipun ini akan dilakukan dengan find . -execatau sth seperti ini: D
Felix Dombek
11

Gabungkan headdan tailsukai dalam dua contoh ini:

$ seq 1 80 | head -n 17 | tail -n 1
17

$ seq 1 10 | head -n 17 | tail -n 1
10

Jadi untuk menyelesaikan masalah Anda yang sebenarnya, perintahnya adalah:

watch 'for f in *; do head -n 17 -- "$f" 2>/dev/null | tail -n 1 ; done'

Catatan tentang 2>/dev/nullbagian ini, itu diperlukan karena * akan cocok dengan direktori dan file apa pun yang Anda mungkin tidak memiliki izin untuk membaca, yang akan menghasilkan pesan kesalahan, yang mungkin ingin Anda sembunyikan.

Hyde
sumber
0

pendekatan lain dengan find, exec dan sed

watch find . -type f -name \"*\" -exec sh -c \'\( printf '%-50s ' {} \; sed -n 17p {}\)\' \\\;
dhanlin
sumber
1
Tidak berfungsi untuk file dengan kurang dari 17 baris. Baca pertanyaan dengan seksama.
Wildcard