Geçici dosya kullanmadan ilk N çıkış satırını sona erdir


11

Gibi bir komutun çıktısını düşünün

44444
55555
11111
22222
33333

ilk N satırını (yukarıdaki örnekte ilk iki) nasıl sıralayabilir ve sonunda ekleyebilirim, ancak geçici dosya kullanmadan (yalnızca borular kullanarak)?

11111
22222
33333
44444
55555

Çizgileri boyunca bir şey | sed -n '3,5p;1,2p'(açıkçası sed olarak çalışmaz, komutların sırasını umursamaz).


2
Neden geçici bir dosyayı kullanamıyoruz?
Braiam

Yanıtlar:


13

Bu satırları bekletme arabelleğine kopyalayın (sonra silin) ​​ve son satırda bekletme arabelleğinin içeriğini desen alanına ekleyin:

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

Onunla gnu sedşöyle yazabilirsin

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

İşte ol 'ile başka bir yol var ed( rçıktısını some commandmetin arabelleğine yönlendirir ve sonra msatırdan 1,NUMBERsonra satırları uzatır $):

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

Belirtildiği gibi, bunların her ikisinde de çıktı NUMBER+1 çizgisinden daha az olursa başarısız olur . Daha sağlam bir yaklaşım ( gnu sedsözdizimi) olacaktır:

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

bu, yalnızca son satır ( $!d) olmadığı sürece bu aralıktaki satırları siler - aksi takdirde tutma arabellek içeriğiyle ( g) ve ardından quits (geçerli kalıp alanını yazdırdıktan sonra) ile desen alanının üzerine yazar .


2
sed -e '1,NUMBER{H;1h;d;}' -e '$G'portatif olarak da çalışır (bazı seduygulamaların tutma alanında birkaç kilobayttan fazla tutamayacağını unutmayın , bu yüzden NUMBER orada çok büyük olamaz)
Stéphane Chazelas

@ StéphaneChazelas - giriş için teşekkürler - Ben genellikle taşınabilir olduğundan emin olarak her satır için bir komut ile gitmek - çoklu ifadeler sözdizimi benim için her zaman biraz kafa karıştırıcı olmuştur örneğin posix dokümanlar "<right-brace> öncesinde bir <newline> " öyleyse onlara göre bu olmamalı sed -e '1,NUMBER{H;1h;d' -e'}' -e '$G'mıydı?
don_crissti

4
Tipik olarak, yeni -ebir satırsonunun yerini alır. d;}henüz POSIX değil, taşınabilir. Bu, bir sonraki POSIX spesifikasyonunda düzeltilecektir. Bkz. Austingroupbugs.net/view.php?id=944#c2720
Stéphane Chazelas

2
@don_crissti teşekkür ederim! neden işe yaradığına dair kısa bir açıklama da ekleyebilmeniz harika olurdu. (Tabii ki bakacağım, ama daha değerli bir cevap
verecekti

Kafamda, portatif olmayan şey açılış ayracı 1,NUMBER{H;1h;d;}hemen sonra noktalı virgül içermiyor. Yine de , çözümü 20 yıl sonra hala parmaklarıma bağlanan SunOS 4.1'de bir hata olabilir . sed
zwol

11

Bir awkyaklaşım:

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

@ Don_crissti'nin sedyaklaşımından bir yararı , çıktıda nçizgiler veya daha az olması durumunda hala çalıştığıdır (satırları çıkarır ) .


Sabit kodu \nORS ile değiştirmek isteyebilirsiniz , böylece bu işlem diğer kayıt ayırıcılarıyla çalışır (paragraflar kullanmak istediğinizi vb.).
fedorqui

6

Ben var xclipve onunla bu şekilde yapılabilir:

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

İşte açıklaması:

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
Xclip öğesinin reklam öğesi (yanlış) kullanımı için +1. Yanıt için erişilebilir / çalışan bir X sunucusu gerekir.
jofel

3

Perl yolu:

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

Veya aynı şey daha az şifreli olarak yazılmıştır:

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

Örneğin:

$ cat file
44444
55555
11111
22222
33333

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

açıklama

  • -ne: giriş dosyasını / akışı satır satır okur ve -eher satıra verilen komut dosyasını uygular .
  • $.<3: $.geçerli satır numarasıdır, bu nedenle değiştirmek 3istediğiniz satır sayısına değiştirin.
  • $.<3?($f.=$_):print;Bu koşullu operatör genel biçimidir olduğunu condition ? case1 : case2, bu çalışacaktır case1eğer conditiondoğruysa ve case2eğer yanlış. Burada, geçerli satır numarası 3'ten küçükse, geçerli satırı ( $_) değişkene ekler $fve satır numarası 3'ten büyükse yazdırır.
  • }{ print $f: }{perl için kestirme END{}. Tüm giriş satırları işlendikten sonra çalışır. Bu noktada, kaydırmak istediğimiz tüm satırları toplayacağız ve yalnız bırakmak istediğimiz tüm satırları basmış olacağız, bu nedenle kaydedilen satırları yazdırın $f.

1
Golf versiyonunuzla ilgili birkaç karakter kaldırılabilirperl -ne '$.<3?$f.=$_:print}{print $f
123

1

POSIX kullanın ex. Evet, dosya düzenleme amaçlıdır, ancak bir ardışık düzende çalışacaktır.

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

Bu, boru hattının başına veya sonuna rastgele komutlar ekleyebilir ve aynı şekilde çalışır. Daha da iyisi, varlığı göz önüne alındığında, /dev/stdinPOSIX uyumludur.

( /dev/stdinPOSIX'te belirtilip belirtilmediğini bilmiyorum , ancak Linux ve Mac OS X'te mevcut olduğunu görüyorum.)

Bunun okunabilirlik sedalanı kullanımına göre okunabilirlik avantajı vardır - sadece ex"bu satırları sonuna taşı " deyin ve öyle yapar. (Komutların geri kalanı "tamponu yazdır" ve "çıkış" anlamına gelir ve bunlar da oldukça okunabilir.)

Not: exGiriş olarak 2 satırdan az verilirse, yukarıda verilen komut başarısız olur.

Daha fazla okuma:


0

Kısa bir pythonpasaj:

#!/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='')

İlk bağımsız değişken olarak dosya adını ve ikinci bağımsız değişken olarak taşınacak satır sayısını iletin.

Misal:

$ 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

Çıktının tamamını bellekte saklayabiliyorsanız:

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

0

İşte GNU gerektiren başka bir seçenek sed:

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

-ukomutun 3 satırdan fazla STDIN tüketmemesi sediçin GNU'nun arabelleksiz olmasını sağlar sed. Komut ikamesi boş satırları kaldırır, böylece üçüncü, üçüncü ve ikinci veya üçüncü, ikinci ve ilk satırlar boşsa komut çıktının sonunda boş satırlar içermez.

Bunun gibi bir şey de yapabilirsiniz:

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

sponge /dev/stdout|Komut olmadan uzun girişlerde başarısız olur. sponge /dev/stdoutAyrıca ile değiştirilebilir tac|tac, örneğin bu baskılar da, a\ncbgiriş ise, a\nb\ncburada \nbir satır besleme, ya da (x=$(cat);printf %s\\n "$x"), hatta giriş ucundan bu kaldırır boş satır bile. Yukarıdaki komut, girişin satır sayısı bir veya iki olduğunda ilk satırı siler.

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.