Pindahkan garis N output pertama untuk mengakhiri tanpa menggunakan file sementara


11

Bayangkan output dari perintah seperti

44444
55555
11111
22222
33333

bagaimana saya bisa menarik garis N pertama (dua yang pertama dalam contoh di atas) dan menambahkannya di akhir, tetapi tanpa menggunakan file temp (jadi hanya menggunakan pipa)?

11111
22222
33333
44444
55555

Sesuatu di sepanjang baris | sed -n '3,5p;1,2p'(yang jelas tidak bekerja karena sed tidak peduli dengan urutan perintah).


2
Mengapa kami tidak dapat menggunakan file temp?
Braiam

Jawaban:


13

Cukup salin baris-baris itu ke hold buffer (lalu hapus mereka) dan ketika pada baris terakhir tambahkan konten hold buffer ke ruang pola:

some command | sed '1,NUMBER{           # in this range
H                                       # append line to hold space and
1h                                      # overwrite if it's the 1st line
d                                       # then delete the line
}
$G'                                     # on last line append hold buffer content

Dengan gnu sedAnda bisa menuliskannya sebagai

some command | sed '1,NUMBER{H;1h;d;};$G'

Inilah cara lain dengan ol ' ed(itu rmenghasilkan keluaran dari some commandke buffer teks dan kemudian moves baris 1,NUMBERsetelah yang $pertama):

ed -s <<IN
r ! some command
1,NUMBERm$
,p
q
IN

Perhatikan bahwa - sebagaimana ditunjukkan - keduanya akan gagal jika output memiliki kurang dari NUMBER+1 baris. Pendekatan yang lebih solid adalah ( gnu sedsintaks):

some command | sed '1,NUMBER{H;1h;$!d;${g;q;};};$G'

yang satu ini hanya menghapus garis dalam rentang itu selama mereka bukan baris terakhir ( $!d) - kalau tidak menimpa ruang pola dengan menahan konten buffer ( g) dan kemudian qmenggunakan (setelah mencetak ruang pola saat ini).


2
sed -e '1,NUMBER{H;1h;d;}' -e '$G'juga bekerja dengan baik (perhatikan bahwa beberapa sedimplementasi tidak dapat menampung lebih dari beberapa kilobyte di ruang penyimpanan, jadi NUMBER tidak boleh terlalu besar di sana)
Stéphane Chazelas

@ StéphaneChazelas - terima kasih atas masukannya - Saya biasanya menggunakan satu perintah per baris karena saya tahu pasti itu portabel - sintaks beberapa ekspresi selalu agak membingungkan bagi saya misalnya dokumen posix mengatakan "The <right-brace> akan menjadi didahului oleh <newline> " jadi menurut mereka, bukankah itu seharusnya sed -e '1,NUMBER{H;1h;d' -e'}' -e '$G'?
don_crissti

4
Biasanya, baru -emenggantikan baris baru. d;}belum POSIX tetapi portabel. Itu akan diperbaiki dalam spesifikasi POSIX berikutnya. Lihat austingroupbugs.net/view.php?id=944#c2720
Stéphane Chazelas

2
@don_crissti terima kasih! alangkah baiknya jika Anda juga bisa memasukkan penjelasan singkat mengapa itu bekerja. (Tentu saja saya akan mencarinya, tetapi itu akan membuat jawaban yang lebih berharga.)
Peter Uhnak

Dalam benak saya, hal 1,NUMBER{H;1h;d;}yang tidak dapat dipercaya tentang tidak memiliki titik koma segera setelah penjepit pembukaan . Itu mungkin saja bug di SunOS 4.1 sedyang solusinya masih ditransfer ke jari saya 20 tahun kemudian.
zwol

11

Suatu awkpendekatan:

cmd | awk -v n=3 '
  NR <= n {head = head $0 "\n"; next}
  {print}
  END {printf "%s", head}'

Satu manfaat dari pendekatan @ don_crisstised adalah bahwa ia masih berfungsi (mengeluarkan garis) jika keluaran memiliki ngaris atau lebih sedikit.


Anda mungkin ingin mengganti hardcoded \ndengan ORS, sehingga ini akan bekerja dengan pemisah rekaman lainnya (misalnya Anda ingin menggunakan paragraf, dll).
fedorqui

6

Saya sudah xclipdan dengan itu ini dapat dilakukan dengan cara ini:

./a_command | xclip -in && xclip -o | tail -n +3 && xclip -o | head -n 2

Berikut uraiannya:

xclip - command line interface to X selections (clipboard)

NAME
       xclip - command line interface to X selections (clipboard)

SYNOPSIS
       xclip [OPTION] [FILE]...

DESCRIPTION
       Reads from standard in, or from one or more files, and makes the data available as an X selection for pasting into X applications. Prints current X selection to standard out.

       -i, -in
              read text into X selection from standard input or files (default)

       -o, -out
              prints the selection to standard out (generally for piping to a file or program)

3
+1 untuk penggunaan xclip yang kreatif (salah). Jawabannya membutuhkan server X yang dapat diakses / dijalankan.
jofel

3

Cara Perl:

perl -ne '$.<3?($f.=$_):print;}{print $f'

Atau, hal yang sama ditulis lebih samar:

perl -ne 'if($.<3){ $f.=$_ } else{ print } END{print $f}'

Sebagai contoh:

$ cat file
44444
55555
11111
22222
33333

$ cat file | perl -ne '$.<3?($f.=$_):print;}{print $f'
11111
22222
33333
44444
55555

Penjelasan

  • -ne: baca file input / stream baris demi baris dan terapkan skrip yang diberikan oleh -euntuk setiap baris.
  • $.<3: $.adalah nomor baris saat ini, jadi ubahlah 3ke jumlah baris yang ingin Anda ubah .
  • $.<3?($f.=$_):print;: ini adalah operator kondisional, format umumnya adalah condition ? case1 : case2, ia akan berjalan case1jika conditionbenar dan case2jika itu salah. Di sini, jika nomor baris saat ini kurang dari 3, itu menambahkan baris saat ini ( $_) ke variabel $fdan, jika nomor baris lebih besar dari 3, itu dicetak.
  • }{ print $f: }{adalah singkatan perl untuk END{}. Ini akan berjalan setelah semua jalur input telah diproses. Pada titik ini, kami akan mengumpulkan semua garis yang ingin kami ubah dan akan mencetak semua yang ingin kami tinggalkan sendiri, jadi cetaklah garis yang disimpan sebagai $f.

1
mengenai versi golf Anda, beberapa karakter dapat dihapusperl -ne '$.<3?$f.=$_:print}{print $f
123

1

Gunakan POSIX ex. Ya, ini dimaksudkan untuk mengedit file, tetapi itu akan berfungsi dalam satu pipeline.

printf %s\\n 111 222 333 444 555 | ex -sc '1,2m$|%p|q!' /dev/stdin

Ini dapat memiliki perintah sewenang-wenang ditambahkan di awal atau akhir pipa dan akan bekerja sama. Lebih baik lagi, mengingat keberadaannya /dev/stdin, itu sesuai dengan POSIX.

(Saya tidak tahu apakah /dev/stdindispesifikasikan dalam POSIX atau tidak, tapi saya melihatnya ada di Linux dan Mac OS X.)

Ini memiliki keunggulan keterbacaan dibandingkan menggunakan sedruang pegang - Anda hanya mengatakan ex"pindahkan garis ini ke akhir" dan itu melakukannya. (Sisa dari perintah berarti "cetak buffer" dan "keluar," yang cukup mudah dibaca juga.)

NB: exPerintah yang diberikan di atas akan gagal jika diberikan kurang dari 2 baris sebagai masukan.

Bacaan lebih lanjut:


0

pythonCuplikan singkat :

#!/usr/bin/env python3
import sys
file_ = sys.argv[1]
lines = int(sys.argv[2])
with open(file_) as f:
    f = f.readlines()
    out = f[lines:] + f[:lines]
    print(''.join(out), end='')

Lulus nama file sebagai argumen pertama dan jumlah baris untuk bergerak sebagai argumen kedua.

Contoh:

$ cat input.txt
44444
55555
11111
22222
33333

$ ./sw_lines.py input.txt 2
11111
22222
33333
44444
55555

$ ./sw_lines.py input.txt 4
33333
44444
55555
11111
22222

0

Jika Anda dapat menyimpan seluruh output dalam memori:

data=$(some command)
n=42                  # or whatever
{ tail -n +$((n+1)) <<<"$data"; head -n $n <<<"$data"; } > outputfile

0

Berikut adalah opsi lain yang membutuhkan GNU sed:

(x=$(gsed -u 3q);cat;printf %s\\n "$x")

-umembuat GNU tidak seddibangun sehingga sedperintah tidak mengkonsumsi lebih dari 3 baris STDIN. Substitusi perintah menghapus baris kosong, sehingga perintah tidak menyertakan baris kosong di akhir output jika baris ketiga, ketiga dan kedua, atau ketiga, kedua, dan pertama kosong.

Anda juga dapat melakukan sesuatu seperti ini:

tee >(sponge /dev/stdout|sed -u 3q)|sed 1,3d

Tanpa sponge /dev/stdout|perintah akan gagal dengan input panjang. sponge /dev/stdoutjuga dapat diganti dengan tac|tac, meskipun yang dicetak misalnya a\ncbjika inputnya adalah di a\nb\ncmana \nlinefeed, atau dengan (x=$(cat);printf %s\\n "$x"), meskipun itu menghapus garis kosong dari akhir input. Perintah di atas menghapus baris pertama ketika jumlah baris input adalah satu atau dua.

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.