En az karakter içeren satır nasıl bulunur


22

Herhangi bir genel UNIX komutunu kullanarak bir kabuk betiği yazıyorum. En az karakter içeren satırı (boşluk dahil) almak zorundayım. 20 hatta kadar olabilir.

head -$L | tail -1 | wc -mL satırının karakter sayısını bulmak için kullanabileceğimi biliyorum . Sorun şu ki, düşünebildiğim tek yöntem, bunu kullanarak, if ifadelerini el ile yazmak ve değerleri karşılaştırarak yapmak.

Örnek veri:

seven/7
4for
8 eight?
five!

4forBu satır en az karaktere sahip olduğundan geri dönecekti .

Benim durumumda, eğer birden çok satır en kısa uzunluğa sahipse, tek bir satır döndürülmelidir. Asgari uzunluktaki olduğu sürece hangisinin seçildiği önemli değildir. Ancak diğer durumlara sahip diğer kullanıcılar için her iki yolu da göstermenin zararını görmüyorum.


5
Ya 4 uzunluğa sahip birden fazla satır varsa? Onlar da basılmalı mı?
kaos,

Benim durumumda, eğer birden çok satır en kısa uzunluğa sahipse, tek bir satır döndürülmelidir. Asgari uzunluktaki olduğu sürece hangisinin seçildiği önemli değildir. Ancak diğer durumlara sahip diğer kullanıcılar için her iki yolu da göstermenin zararını görmüyorum.
Matthew D. Scholefield

Yanıtlar:


13

Perl yolu. Aynı en kısa uzunlukta birçok satır varsa, bu yaklaşımın bunlardan yalnızca birini basacağını unutmayın:

perl -lne '$m//=$_; $m=$_ if length()<length($m); END{print $m if $.}' file 

açıklama

  • perl -lne: -n"girdi dosyası satır satır satır oku" anlamına gelir, -lizleyen her satırın her satırdan kaldırılması ve her printaramaya eklenecek yeni satır olması ; ve -eher satıra uygulanacak komut dosyası.
  • $m//=$_: tanımlanmadıkça $mgeçerli satıra ( $_) ayarlanır $m. //=Operatör Perl 5.10.0 beri mevcuttur.
  • $m=$_ if length()<length($m): Geçerli değerin $muzunluğu, geçerli satırın uzunluğundan büyükse, geçerli satırı ( $_) olarak kaydedin $m.
  • END{print $m if $.}: tüm satırlar işlendikten sonra $m, en kısa satırın geçerli değerini yazdırın . Bunun if $.yalnızca satır numarası ( $.) tanımlandığında gerçekleşmesini ve boş girdi için boş bir satır yazdırılmasını önleyerek olmasını sağlar .

Alternatif olarak, dosyanız belleğe sığacak kadar küçük olduğundan, şunları yapabilirsiniz:

perl -e '@K=sort{length($a) <=> length($b)}<>; print "$K[0]"' file 

açıklama

  • @K=sort{length($a) <=> length($b)}<>: <>Burada, elemanları dosyanın satırları olan bir dizi var. sortUzunluklarına göre sıralamak ve kriteri hatlar dizisi olarak kaydedilir @K.
  • print "$K[0]": dizinin ilk elemanını basar @K: en kısa satır.

Yazdırmak istediğiniz takdirde tüm kısa çizgiler, kullanabilirsiniz

perl -e '@K=sort{length($a) <=> length($b)}<>; 
         print grep {length($_)==length($K[0])}@K; ' file 

1
-CUzunluğu bayt sayısı yerine karakter sayısı cinsinden ölçmek için ekleyin . Bir UTF-8 yerel ayarında, (2 vs 3) karakterinden daha $$az bayt var , ancak daha fazla karakter (2 vs 1) var.
Stéphane Chazelas

17

İle sqlite3:

sqlite3 <<EOT
CREATE TABLE file(line);
.import "data.txt" file
SELECT line FROM file ORDER BY length(line) LIMIT 1;
EOT

Bu benim en sevdiğimdir, hiç SQL düşünmedim ...
kaos

2
Bu kod golf durumu zeki
shadowtalker

2
Bu işlem tüm dosyayı belleğe okur mu ve / veya diskte ikinci bir kopya oluşturur mu? Eğer öyleyse, zeki ama verimsiz.
John Kugelman,

1
@JohnKugelman Bu, muhtemelen 4 satırın tümünü geçici bir hafızaya, sadece veritabanına batırır (bu, stracegösterdiği şey). Gerçekten büyük dosyalarla çalışmanız gerekiyorsa (ve sisteminiz değişmiyorsa), onu sadece bir dosya adı ekleyerek zorlayabilirsiniz sqlite3 $(mktemp)ve tüm veriler diske yazılır.
FloHimself

Aşağıdaki hataları alıyorum: "" "xaa: 8146: çıkamayan" karakter "" "ve" "" xaa: 8825: 1 sütun bekleniyor, ancak "-" yok sayılan 2 ek bulundu. Dosya her satırda 1 adet json belgesinden oluşuyor .
Ahmedov

17

İşte awkbulunan ilk minimum satırı yazdırmak için bir çözüm varyantı :

awk '
  NR==1 || length<len {len=length; line=$0}
  END {print line}
'

tüm minimum satırları yazdırmak için tek bir koşulla genişletilebilir:

awk '
  length==len {line=line ORS $0}
  NR==1 || length<len {len=length; line=$0}
  END {print line}'
'

12

Python oldukça özlü bir şekilde ortaya çıkıyor ve kod Teneke Ne Diyor?

python -c "import sys; print min(sys.stdin, key=len),"

Son virgül belirsiz, itiraf ediyorum. Print cümlesinin ek bir satır sonu eklemesini önler. Ek olarak, Python 3'te aşağıdaki gibi 0 satırı destekleyen yazabilirsiniz:

python3 -c "import sys; print(min(sys.stdin, key=len, default='').strip('\n'))"


Teneke ne diyor?
mikeserv

@mikeserve: "sys.stdin değerini minimum, len'i anahtar olarak kullanarak yazdırıyor" yazıyor ;-)
Steve Jessop

1
ahh. İkili boyut, bağımlılık sünme veya yürütme süresi hakkında hiçbir şey, o zaman?
mikeserv

2
@mikeserv: hayır, küçük baskı teneke üzerinde değil. Kilitli bir dosya dolabında, bir kilerde, "leopardan sakının" yazan bir kapının ardındaki bir danışma broşüründe.
Steve Jessop,

Gotcha - yani ekranda.
mikeserv

10

Saf kabuk komut dosyası içeren çözümleri her zaman seviyorum (exec!).

#!/bin/bash
min=
is_empty_input="yes"

while IFS= read -r a; do
    if [ -z "$min" -a "$is_empty_input" = "yes" ] || [ "${#a}" -lt "${#min}" ]; then
        min="$a"
    fi
    is_empty_input="no"
done

if [ -n "$a" ]; then
    if [ "$is_empty_input" = "yes" ]; then
        min="$a"
        is_empty_input="no"
    else
        [ "${#a}" -lt "${#min}" ] && min="$a"
    fi
fi

[ "$is_empty_input" = "no" ] && printf '%s\n' "$min"

Not :

Girişte NUL baytlarında bir sorun var. Yani, yerine printf "ab\0\0\ncd\n" | bash this_scriptyazdırır .abcd


Bu gerçekten en saf olanı. Bununla birlikte, testlerin sakarlanması bashbeni sortbunun yerine ara bir sonuç vermeye ikna edecektir .
orion

2
No exec'inizi tezgahlamayı denediniz mi ? başkalarına karşı çözüm nedir? İşte exec arasındaki performans farklarının karşılaştırması ! ve idam yok! benzer bir problem için çözümler. gibi şekillerde -, ayrı bir işlem execing bu örümcekler zaman çok nadiren avantajlıdır var=$(get data)Bu veriler, tek bir bağlama akımı kısıtlamasını - ancak veri taşıdığınızda ile bir boru hattı - akımında - her uygulanan exec genellikle yararlı - bu özel kılar, çünkü Modüler programların sadece gerekli yerlerde uygulanması.
mikeserv

1
@DigitalTrauma - genişletilmiş bitişik bir rakam dizisi, diğer herhangi bir genişletilmiş dizgeden daha fazla kabuk alıntı yapmak şartlarından muaf değildir. $IFSsayısal ayrımcı değildir - varsayılan $IFSdeğerde hiçbiri olmasa bile, birçok kabuk önceden belirlenmiş bir ortam yapılandırmasını kabul eder $IFS- ve bu nedenle bu özellikle güvenilir bir varsayılan değildir.
mikeserv


1
Yorumlarınız ve olumlu yorumlarınız için hepinize teşekkür ederiz (bazı temsilciler yanıtımı düzeltmek için @ cunonglm adresine gitmelidir). Genel olarak başkalarına günlük olarak saf kabuk komut dosyası çalıştırmalarını önermiyorum, ancak bu beceri statik bağlantıdan başka hiçbir şeyin olmadığı bazı zorlu koşullarda çok yararlı olabilir /bin/sh. SunOS4 sunucularının /usrkaybedilmiş veya bir kısmı .sozarar görmüş durumdayken birkaç kez başıma geldi ve şimdi modern Linux çağında, bazen de gömülü sistemler veya önyükleme başarısız sistemlerinin başında benzer durumlarla karşılaşıyorum. BusyBox, son zamanlarda edindiğimiz harika şeylerden biri.
yaegashi

9

İşte saf bir zshçözüm (tüm çizgileri en az uzunlukta yazdırır file):

IFS=$'\n'; print -l ${(M)$(<file):#${~${(o@)$(<file)//?/?}[1]}}

Örnek giriş:

seven/7
4for
8 eight?
five!
four

Çıktı:

4for
four

Kısa bir açıklamaya ihtiyacı olduğunu düşünüyorum :-)


İlk önce iç alan ayırıcısını newline olarak ayarladık:

IFS=$'\n';

Şimdiye kadar çok iyi, şimdi zor kısmı. printkullanır-lBayrağı, sonucu boşluklar yerine yeni satırlarla ayırarak yazdırmak için .

Şimdi içeriden başlayalım:

$(<file)

Dosya satır satır okunur ve dizi olarak kabul edilir. Sonra:

${(o@)...//?/?}

oBayrak sonucu, artan sırada sipariş edilmesi gerektiğini söyler @de dizi olarak sonuç tedavi etmek anlamına gelir. Arkasında kalan ( //?/?), yerine geçen tüm karakterleri a ile değiştirir ?. Şimdi:

${~...[1]}

[1]Sizin durumunuzda şimdiki en kısa olan ilk dizi elemanını alıyoruz ????.

${(M)$(<file):#...}

Eşleştirme, her bir dizi öğesinde ayrı olarak gerçekleştirilir ve eşleşmeyen dizi öğeleri kaldırılır ( M). Eşleşen her öğe???? (4 karakter) dizide kalır. Yani kalan elemanlar 4 karakterden (en kısa olanları) oluşuyor.

Düzenleme: Yalnızca en kısa satırlardan birine ihtiyacınız varsa, bu değiştirilmiş sürüm birinciyi yazdırır:

IFS=$'\n'; print -l ${${(M)$(<file):#${~${(o@)$(<file)//?/?}[1]}}[1]}

8
tr -c \\n 1 <testfile |   #first transform every [^\n] char to a 1
grep -nF ''           |   #next get line numbers
paste -d: - testfile  |   #then paste it together with itself
sort  -t: -nk2,2          #then sort on second field

... ve kazanan ... satır 2, öyle görünüyor.

2:1111:4for
4:11111:five!
1:1111111:seven/7
3:11111111:8 eight?

Ancak bununla ilgili sorun, çalışabilmesi için her hattın iki katından daha uzun olması gerekir - yani LINE_MAX etkin bir şekilde yarıya iner. Nedeni kullanıyor olması - ne, bir baz 1? - hattın uzunluğunu temsil etmek. Benzer ve belki de daha düzenli bir yaklaşım, bu bilgiyi akışta sıkıştırmak olabilir. Bu satırlar boyunca meydana gelen ilk fikir, benim yapmam gerekenlerdi unexpand:

tr -c \\n \  <testfile    |   #transform all [^\n] to <space>
unexpand -t10             |   #squeeze every series of 10 to one tab
grep -nF ''               |   #and get the line numbers
sed    's/:/!d;=;:/;h;:big    #sed compares sequential lines
$P;$!N; /\(:[^ ]*\)\( *\)\n.*\1.*\2/!D     #newest line is shorter or...
        g;/:./!q;b big'   |   #not; quit input entirely for blank line
sed -f - -e q testfile        #print only first occurrence of shortest line

Bu yazdırır ...

2
4for

Bir tane daha, sadece sed:

sed -n '/^\n/D;s/\(.\)\(\n.*\)*/\1/g
$p;h;   s// /g;G;x;n;//!g;H;s// /g
G;      s/^\( *\)\(\n \1 *\)\{0,1\}\n//
D'      <infile >outfile

Sözdizimi standartlara uygundur - ancak bu eskilerin hiçbirinin garantisi değildir. sed kullanımına .\(reference-group\)\{counts\} doğru şekilde değildir - çoğu yok.

Temelde aynı regexp'i tekrar tekrar girişe uygular - bu onları derleme zamanı geldiğinde çok faydalı olabilir. Bu model:

\(.\)\(\n.*\)*

Farklı şekillerde farklı dizelerle eşleşir. Örneğin:

string1\nstring2\nstring3

... siçinde \1ve ''içinde boş bir dize ile eşleşir \2.

1\nstring2\nstring3

... 1içinde \1ve \nstring2\nstring3içinde ile eşleşir\2

\nstring2\nstring3

... \niçinde \1ve ''içinde boş bir dize ile eşleşir \2. \nDesen uzayının başında bir sınır çizgisi oluşma olasılığı varsa - ve /^\n/D, //!gbunu önlemek için komutlar kullanılırsa bu sorunlu olurdu . Kullandım [^\n]ama bu küçük senaryo için diğer ihtiyaçlar taşınabilirliği bir endişe haline getirdi ve çoğu zaman yanlış yorumlandığı birçok yoldan memnun değildim. Artı, .daha hızlı.

\nstring2
string1

... maç \nve stekrar \1ve elde hem ''de boş dize \2. Boş çizgiler hiç uyuşmuyor.

Desen, globally uygulandığında , iki önyargı - hem en soldaki standart önyargı hem de daha küçük olan sağ \nkenardaki ön kenar önyargısı - bir atlamayı etkilemek için karşı dengededir. Birkaç örnek:

s/\(.\)\(\n.*\)*/\1:\2/g
s/\(.\)\(\n.*\)*/\2\1:/g
s/\(.\)\(\n.*\)*/\1: /g
s/\(.\)\(\n.*\)*/ :\2/g

... tümü aşağıdaki sıraya uygulanırsa (arka arkaya değil) ...

string1\nstring2

... dönüştürecek ...

s:t:r:i:n:g:1:\nstring2
s:t:r:i:n:g:\nstring21:
s:t:r:i:n:g:1: 
 : : : : : : :\nstring2

Temel olarak regexp'i uygulayacağım herhangi bir desen-uzayda her zaman sadece ilk satırı işlemek için kullanırım. Bu, hem tutulan en kısa eşleşme çizgisinin iki farklı versiyonunu hem de test döngülerine başvurmadan en yeni çizgiyi atmamı sağlıyor - uygulanan her ikame tüm desen alanını bir kerede ele alıyor.

Değişken dizge / dizge karşılaştırmaları için farklı sürümler gereklidir - bu nedenle tüm karakterlerin eşit olmasını garantileyen her satırın bir sürümü olmalıdır. Ancak, eğer biri ya da diğeri aslında girişte en kısa zamanda ortaya çıkan en kısa çizgi olmalıysa, çıktı için yazdırılan çizgi muhtemelen çizginin orijinali olmalıdır - karşılaştırma için sterilize ettiğim / homojenize ettiğim değil. Ve böylece her birinin iki versiyonuna ihtiyacım var.

Başka bir zorunluluğun aynı işlemi yapmak için çok fazla tampon geçişi olması talihsiz bir durumdur - ama en azından hiçbirinde tampon hiçbir zaman güncel kalmak için gereken dört çizgiden daha fazlasını geçemez - ve bu yüzden belki de korkunç değildir.

Her neyse, her döngü için olan ilk şey hatırlanan hatta bir dönüşümdür - çünkü gerçekte kaydedilen tek kopya değişmez orijinaldir - içine ...

^               \nremembered line$

... ve sonra next giriş satırı eski tamponların üzerine yazar. En az bir karakter içermiyorsa, etkin bir şekilde göz ardı edilir. Sadece çok daha kolay olurduq ortaya çıkan ilk boş satırda , ama, test verilerimde bunlardan çok daha fazlası vardı ve birden çok paragrafla ilgilenmek istedim.

Ve eğer karakter içeriyorsa, edebi versiyonu hatırlanan çizgiye eklenir ve aralıklı karşılaştırma versiyonu kalıp boşluğunun başında bulunur, şöyle:

^   \n               \nremembered line\nnew$

Son olarak, bu model alanına bir ikame uygulanır:

s/^\( *\)\(\n \1 *\)\{0,1\}\n//

Bu yüzden eğer yeni satır, hatırlanan satırı, en az bir karakterin yedeklenmesi gereken boşluğu içerecek şekilde sığdırabilirse, ilk iki satır yerine, sadece ilk satır konulur.

DSonuçtan bağımsız olarak, desen uzayındaki ilk satır, yeniden başlamadan önce her zaman döngü sonunda ortaya çıkar. Bunun anlamı eğer yeni satır son diziden daha kısaysa ...

new

... her zaman yalnızca ilk satırdaki satırdan sıyrılacak olan döngüdeki ilk yer değiştirmeye geri gönderilir - ve böylece bütün kalır. Ama o zaman dize değilse ...

remembered line\nnew

... bunun yerine bir sonraki döneme başlayacak ve ilk yerleşme ondan sıyrılacak ...

\nnew

...her zaman.

En son satırda, hatırlanan satır standart çıktıya yazdırılır ve bu nedenle verilen örnek veriler için yazdırır:

4for

Ancak, cidden, kullanın tr.



Satır numarası eklemeniz bile gerekiyor mu? OP'yi okumam, sadece en kısa satırın gerekli olduğudur ve mutlaka o satırın satır numarası değildir. Bütünlüğü göstermek için hiçbir zararı yok sanırım.
Dijital Travma

@ DigitalTrauma - nah, muhtemelen değil. Ama onlarsız pek faydalı olmaz - ve çok ucuza gelirler. Bir akışı çalıştırırken, her zaman orijinal girişi çıktıda aynı şekilde çoğaltmanın bir yolunu eklemeyi tercih ederim - satır numaraları burada bunu mümkün kılar. Örneğin, ilk boru hattı, etrafımızda sonuçlarını açmak için: REINPUT | sort -t: -nk1,1 | cut -d: -f3-. İkincisi, sed --expressionkuyruğa başka bir senaryo eklemek basit bir meseledir .
mikeserv

@DigitalTrauma - Oh ve ilk örnekte satır numaraları yok etkiler sortaynı uzunlukta hatları girişi meydana geldiğinde bir bağlayıcı-kesici olarak davranışını - erken ortaya çıkan satır, her zaman, bu durumda üst kısmında yüzen çok.
mikeserv

7

Deneyin:

awk '{ print length, $0 }' testfile | sort -n | cut -d" " -f2- | head -1

Fikir awkilk önce her satırın uzunluğunu yazdırmak için kullanmaktır . Bu görünecektir:

echo "This is a line of text" | awk '{print length, $0}'
22 This is a line of text

Ardından tarafından satırları sıralamak için karakter sayısı kullanmak sort, cutsayım kurtulmak için ve headilk satırı (en az karakter olan) tutmak. Elbette tail, bu durumda en çok karaktere sahip çizgiyi elde etmek için kullanabilirsiniz .

(Bu cevaptan kabul edildi )


Mantık için +1, ancak her durumda işe yaramaz. İki satır aynı sayıda karakter içeriyorsa ve minimum düzeyde ise. Size sadece karşılaştığı ilk satırı verecekhead -1
08'de

En uzun çizgiyi elde etmek için, sıralamayı kullanmaktan daha tersine çevirmek biraz daha etkilidir tail( headişi biter bitmez, girişinin kalanını okumadan çıkabilirsiniz).
Toby Speight

@Thushi Bir miktar regex kullanarak, satır numaralarını yazdırdıktan sonra, satır 1 ile aynı sayıdaki satırlar dışındaki her şey kaldırılabilir, böylece en kısa satırların tümü çıkarılabilir.
Matthew D. Scholefield

5

POSIX awk ile:

awk 'FNR==1{l=$0;next};length<length(l){l=$0};END{print l}' file

Birden fazla satır aynı sayıda karaktere sahipse ve aynı zamanda minimum ise işe yaramaz.
Thushi

@Thushi: İlk minimum satırı rapor edecek.
cuonglm

Evet ama bu doğru çıktı değil mi? Diğer satırlar bile minimum karakter sayısına sahiptir.
Thushi

1
@Thushi: OP gerekliliklerinden bahsetmiyor, OP'den güncelleme bekliyor.
cuonglm

3
LDeğişkeni min
adlandırmayı seçmenin

3

@ Mikeserv'in bazı fikirlerini ödünç almak:

< testfile sed 'h;s/./:/g;s/.*/expr length "&"/e;G;s/\n/\t/' | \
sort -n | \
sed -n '1s/^[0-9]+*\t//p'

İlki sedaşağıdakileri yapar:

  • h orijinal satırı tutma arabelleğine kaydeder.
  • Satırdaki her karakteri değiştirin :- bu kod enjeksiyon tehlikesini ortadan kaldırmaktır
  • Tüm satırı değiştir expr length "whole line"- bu değerlendirilebilecek bir kabuk ifadesidir
  • E komutus , kalıp uzayını değerlendirmek ve sonucu tekrar kalıp uzayına koymak için bir GNU sed uzantısıdır .
  • G desen alanına yeni bir satır ekler ve tutma alanı (orijinal satır) içeriğini ekler
  • final s, newline'ı bir sekme ile değiştirir

Karakter sayısı artık her satırın başında bir sayıdır, bu nedenle sort -nsatır uzunluğuna göre sıralar.

Nihai seddaha sonra ilk (en kısa) hattı ve hat uzunluğu ve baskı sonucu tüm ama kaldırır.


1
@mikeserv Evet expr, burada daha iyi olduğunu düşünüyorum . Evet, eher satır için bir kabuk ortaya çıkar. Sed ifadesini dizgideki her karakterin yerine :, kod enjeksiyon olasılığını ortadan kaldırması gerektiğini düşündüğüm değerlendirmeden önceki ile değiştirdim .
Dijital Travma

Genelde xargs exprkişisel olarak tercih ederdim - ama, bir ara kabuktan kaçınmaktan başka, muhtemelen stilistik bir şey. Neyse, hoşuma gitti.
mikeserv

3

Tek bir sedifadede her şeyin mümkün olduğu aklıma geldi . Güzel değil:

$ sed '1h;s/.*/&\n&/;G;:l;s/\n[^\n]\([^\n]*\)\n[^\n]/\n\1\n/;tl;/\n\n/{s/\n.*//;x};${x;p};d' testfile
4for
$ 

Bunu yıkmak:

1h            # save line 1 in the hold buffer (shortest line so far)
s/.*/&\n&/    # duplicate the line with a newline in between
G             # append newline+hold buffer to current line
:l            # loop start
s/\n[^\n]\([^\n]*\)\n[^\n]/\n\1\n/
              # attempt to remove 1 char both from current line and shortest line
tl            # jump back to l if the above substitution succeeded
/\n\n/{       # matches if current line is shorter
  s/\n.*//    # remove all but original line
  x           # save new shortest line in hold buffer
}
${            # at last line
  x           # get shortest line from hold buffer
  p           # print it
}
d             # don't print any other lines

OS X’de bulunan BSD, yeni hatlarla biraz daha titiz. Bu sürüm sed hem BSD ve GNU sürümleri için çalışır:

$ sed -e '1h;G;s/\([^\n]*\)\(\n\)\(.*\)/\1\2\1\2\3/;:l' -e 's/\(\n\)[^\n]\([^\n]*\n\)[^\n]/\1\2/;tl' -e '/\n\n/{s/\n.*//;x;};${x;p;};d' testfile
4for
$

Bunun, en iyi uygulama yanıtını vermek için yapılan ciddi bir girişimden ziyade "mümkün olduğu için" cevabından daha fazlası olduğuna dikkat edin. Sanırım çok fazla kod-kod çalıyordum.


@mikeserv man sedOS X'den: "Kaçış dizisi \ n, desen alanına gömülü yeni bir satır karakteriyle eşleşiyor" . Bu yüzden GNU sed'in \nregex ve replasmana izin verdiğini düşünüyorum , oysa BSD sadece regex'e izin veriyor ve replasmana izin \nvermiyor.
Dijital Travma

\nDesen uzayından ödünç almak iyi bir fikirdir ve ikinci s///ifadede işe yarayacaktır , ancak s/.*/&\n&/ifade daha \nönce bulunmadığı bir model boşluğuna ekliyor. Ayrıca BSD sed, etiket tanımlarından ve dallardan sonra hazır bilgi satırları gerektiriyor.
Dijital Travma

1
Bu yeni satırlar parametre sınırlayıcılarıdır - isteğe bağlı bir parametre kabul edebilecek herhangi bir komutu sınırlandırmak için onlara gereksiniminiz vardır - en azından belirtildiği gibi. Spesifikasyon ayrıca, bir sedkomut dosyasının yeni bir satırda bitmesi gerekmemesi dışında bir metin dosyası olacağını söylüyor . Bu yüzden genellikle onları ayrı ayrı argümanlar gibi sınırlandırabilirsiniz - sed -e :\ label -e :\ label2ve böyle devam eder. 1hYine de yaptığınız x;Hiçin, yeni hattınızı almak için sadece bazı mantıklara geçebilirsiniz - ve w / satırında yeni bir satır çekmeden, satırın sonundaki yeni bir alanı satır sonundan uzatabilirsiniz D.
mikeserv

@mikeserv Güzel. Evet, Gilkini yaparak ve s///ifadeyi değiştirerek ihtiyacım olan yeni satırı ekledim . Kullanarak -eayırmak, hepsinin değişmez yeni satırlar olmadan bir (uzun) hatta gitmesini sağlar.
Dijital Travma

\nKaçış için spec 'olduğu sedda 'ın LHS'nin ve ben o POSIX braket ifadeler aynı zamanda tüm karakterler kendi özel bir anlamı kaybetmek şekilde spec 'yapılır, ardından kelimesi kelimesine Spec ifadesi olduğunu düşünüyorum - (açıkça dahil \\) - bir parantez dışında bir aralık ayırıcı olarak tire ve nokta, eşittir, şapka, harmanlama için sütun, denklik, olumsuzlama ve sınıflar.
mikeserv

2

Başka bir perl çözümü: çizgileri bir dizide saklayın, karma anahtarı çizgi uzunluğudur. Ardından, satırları minimum tuşla yazdırın.

perl -MList::Util=min -ne '
    push @{$lines{ length() }}, $_;
} END {
    print @{$lines{ min keys %lines }};
' sample 
4for

Sen push @{$lines{+length}};ve print @{$lines{+min keys %lines}};daha az yazmak için kullanabilirsiniz :)
cuonglm

Eğer golf oynasaydım, "lines" değişken adını da kullanmazdım:perl -MList::Util=min -nE'push @{$l{+length}},$_}END{say@{$l{min keys%l}}' sample
glenn jackman

Sadece baskı tüm değişken için olsa, golf oynamayan bir sürüm için +1 (çalışır!) . - Kriptik doğasına perluygun olmayan bizler için biraz sersemletir perl. BTW. golf saytutkunu, çıktının sonunda sahte bir boş satır basar.
Peter.O,

2

Sadece ilk kısa çizgiyi elde etmek için:

f=file; sed -n "/^$(sed 's/./1/g' $f | sort -ns | sed 's/././g;q')$/{p;q}" $f

Bütün kısa liflerin, sadece değişimi almak için {p;q}içinp


Başka bir yöntem (biraz sıra dışı), sortgerçek sıralamayı uzunluğa göre yapmaktır . Kısa çizgilerle bile nispeten yavaştır ve çizgi uzunluğu arttıkça önemli ölçüde yavaşlar.
Ancak, üst üste binen anahtarlarla sıralama fikrini buldum oldukça ilginç . Başkalarının da ilginç / bilgilendirici bulabileceği durumlarda gönderiyorum.

Nasıl çalışır:
Aynı tuşun uzunluk değişkenlerine göre sırala - key 1tüm satırı kaplar
Her art arda gelen anahtar değişkeni, anahtar uzunluğunu bir karakter kadar, dosyanın en uzun satırının uzunluğuna kadar artırır (tarafından belirlenir wc -L)

Sadece ilk (sıralanmış) en kısa satırı almak için:

f=file; sort -t'\0' $(seq -f "-k1.%0.0f" $(<"$f" wc -L) -1 1) "$f" | head -n1

ki aynı:

f=file.in; 
l=$(<"$f" wc -L)
k=$(seq -f "-k1.%0.0f" $l -1 1) 
sort -st'\0' $k "$f" | head -n1

2

Boş satırların en kısa satır olarak kabul edilmediğini ve boş satırların olabileceğini varsayarsak, aşağıdaki saf AWK çalışacaktır:

awk '
    {
        len   = length;
        a[$0] = len
    }
    !len { next }
    !min { min = len }
    len < min { min = len }
    END {
        for (i in a)
            if (min == a[i])
                print i
    }
' infile.txt

2

Sıralama kullanmaya ne dersiniz?

awk '{ print length($0) "\t" $0 }' input.txt | sort -n | head -n 1 | cut -f2-

1

GNU ile awk

gawk '
    {
         a[length]=$0
    };
    END
    {
        PROCINFO["sorted_in"]="@ind_num_asc";
        for (i in a)
        {
            print a[i]; 
            exit
        }
    }
    ' file
  • Her satırı, satır uzunluğu ile indekslenmiş bir diziye okuyun.

  • Dizi taramayı , dizi tarafından sıralanmaya ve sayısal olarak sıralanmaya zorlamak PROCINFO["sorted_in"]için ayarlayın@ind_num_asc

  • PROCINFOYukarıdaki şekilde ayarlanması , dizinin geçişinde ilk önce alınacak en küçük uzunlukta çizgiyi zorlar. Yani diziden ilk elemanı bas ve çık

Bunun bir nlognsüre olmasının dezavantajı var , diğer yaklaşımların bazıları nzamanında


1

Orta seviye kabuk araçları yöntemi, hayır sedya da awk:

f=inputfile
head -n $(xargs -d '\n' -L 1 -I % sh -c 'exec echo "%" | wc -c' < $f | 
          cat -n | sort -n -k 2 | head -1 | cut -f 1)  $f | tail -1

Bir $fdeğişkene ihtiyaç duymamak güzel olurdu ; Bir teeşekilde kullanarak mümkün olabilecek bir fikrim var ...
agc
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.