Bash golf için ipuçları


55

Bash'te golf oynamak için hangi genel ipuçlarınız var? Genel olarak golf problemlerini kodlamak için uygulanabilecek fikirleri arıyorum, en azından biraz Bash'e özgüdür (örneğin, "yorumları kaldır" bir cevap değildir). Lütfen cevap başına bir ipucu gönderin.

Yanıtlar:


36

Belgelenmemiş , ancakshgeriye dönük uyumlulukiçin karşılaştığım her sürümde çalışıyor:

fordöngüler { }yerine kullanmanıza izin verir do done. Örneğin, değiştirin:

for i in {1..10};do echo $i; done

ile:

for i in {1..10};{ echo $i;}

Hangi kabuk nedir shve hangi kabuk bu forsözdizimine izin verir ? açıkça izin verilir zsh.
mikeserv

@mikeserv Bash. Bazı yerlerde bu sözdizimine izin verildiğini shve ne yazık ki alıntı yapmadığım halde Bash'in de buna izin verdiğini bir yerde okuduğumu hatırlıyorum .
Dijital Travma

ahh ... csh, muhtemelen - o kabukta böyle çalıştılar.
mikeserv

Bu arada, ksh93yukarıdaki şey olabilir:, ;{1..10}ve içinde bash:printf %s\\n {1..10}
mikeserv

1
for((;i++<10)){ echo $i;}daha kısadırfor i in {1..10};{ echo $i;}
Evan Krall

29

Aritmetik genişleme için $[…]yerine kullanın $((…)):

bash-4.1$ echo $((1+2*3))
7

bash-4.1$ echo $[1+2*3]
7

Aritmetik genişlemelerde kullanmayın $:

bash-4.1$ a=1 b=2 c=3

bash-4.1$ echo $[$a+$b*$c]
7

bash-4.1$ echo $[a+b*c]
7

Aritmetik genişleme, dizine alınmış dizi abonelerinde gerçekleştirilir, bu nedenle hiçbirini kullanmayın $:

bash-4.1$ a=(1 2 3) b=2 c=3

bash-4.1$ echo ${a[$c-$b]}
2

bash-4.1$ echo ${a[c-b]}
2

Aritmetik genişlemelerde kullanmayın ${…}:

bash-4.1$ a=(1 2 3)

bash-4.1$ echo $[${a[0]}+${a[1]}*${a[2]}]
7

bash-4.1$ echo $[a[0]+a[1]*a[2]]
7

Değiştirmek while((i--)), hangisi işe yarıyor while[i--]yada while $[i--]benim için işe yaramadı. GNU bash, sürüm 4.3.46 (1)
Glenn Randers-Pehrson

1
Doğru, @ GlennRanders-Pehrson. Bu işe yaramayacaktı.
Manat çalışması

y=`bc<<<"($x*2.2)%10/1"`... bctamsayılı olmayan hesaplamalar için kullanma örneği ... /1sonundaki sonuçta bir ondalık sayıyı keser.
12'de roblogic

s=$((i%2>0?s+x:s+y))... ternary operatörü bash aritmetiğinde kullanma örneği. if..then..else[ ] && ||
Ondan

1
@ manatwork Teşekkürler. Çıkarmış olmalılar. Ben varım GNU bash, version 5.0.2(1)-release (x86_64-apple-darwin16.7.0)ve o benim içimde değil.
Jonah

19

Bir işlevi tanımlamanın normal, uzun ve sıkıcı yolu

f(){ CODE;}

Gibi bu adam öğrendim, kesinlikle önce yer ihtiyacı CODEve peşine noktalı virgül.

Bu @DigitalTrauma'dan öğrendiğim küçük bir püf noktası :

f()(CODE)

Bu, iki karakter daha kısadır ve fonksiyonun geri dönmesinden sonra değişkenlerin değerlerinde herhangi bir değişiklik yapmanıza gerek kalmaması şartıyla, aynı şekilde çalışır ( parantez gövdeyi bir alt kabukta çalıştırır ).

As @ jimmy23013 yorumlarda işaret, hatta parantez gereksiz olabilir.

Bash aşağıdaki gibi fonksiyonlar tanımlanabilir göstermektedir:

name () compound-command [ redirections ]

veya

function name [()] compound-command [ redirections ]

Bir bileşik komut olabilir:

  • bir döngü yapısı: until, whileya dafor
  • Şartlı yapısı: if, case, ((...))ya da[[...]]
  • Gruplandırılmış Komutlar: (...)veya{...}

Bu, aşağıdakilerin tümü geçerli olduğu anlamına gelir:

$ f()if $1;then $2;fi
$ f()($1&&$2)
$ f()(($1))                # This one lets you assign integer values

Ve enayi gibi kıvrımlı parantez kullanıyorum ...


2
Ayrıca f()while ... f()if ...ve diğer bileşik komutları da kullanabileceğinizi unutmayın .
jimmy23013

Bu beni şaşırttı çünkü f()CODEyasal olduğunu düşündüm . f()echo hiPdksh ve zsh'da yasal olduğu, ancak bash'ta olmadığı ortaya çıktı .
saat

1
forkonumsal olarak varsayılan ayarlardan beri özellikle faydalıdır : f()for x do : $x; done;set -x *;PS4=$* f "$@"veya başka bir şey.
mikeserv

16

:hiçbir şey yapmayan bir komuttur, çıkış durumu daima başarılıdır, bu nedenle yerine kullanılabilir true.


Bir alt kabuk ve boru kullanmak, aynı sayıda bayt kullanır, ancak borulamak daha pratik olur.
ckjbgames

5
Yaptığın zaman hariç:(){:|:}
enedil 17:17

14

Daha fazla ipucu

  1. Üçlü operatörü kötüye kullanmak, ((test)) && cmd1 || cmd2veya [ test ] && cmd1 || cmd2mümkün olduğunca.

    Örnekler (uzunluk sayıları her zaman üst satırı hariç tutar):

    t="$something"
    if [ $t == "hi" ];then
    cmd1
    cmd2
    elif [ $t == "bye" ];then
    cmd3
    cmd4
    else
    cmd5
    if [ $t == "sup" ];then
    cmd6
    fi
    fi

    Sadece üçlü operatörleri kullanarak, bu kolayca kısaltılabilir:

    t="$something"
    [ $t == "hi" ]&&{
    cmd1;cmd2
    }||[ $t == "bye" ]&&{
    cmd3;cmd4
    }||{
    cmd5
    [ $t == "sup" ]&&cmd6
    }

    Nyzzika7h yorumlarda da belirtildiği gibi, bu özel örnek kullanarak daha da kısaltılabilir case:

    t="$something"
    case $t in "hi")cmd1;cmd2;;"bye")cmd3;cmd4;;*)cmd5;[ $t == "sup" ]&&cmd6;esac
  2. Ayrıca, parantezleri mümkün olduğunca parantez içine alın. Parantezler bir meta karakterdir ve sözcük değildir, hiçbir bağlamda boşluk gerektirmezler. Bu aynı zamanda, bir alt kabukta mümkün olduğu kadar çok komut çalıştırmak anlamına gelir, çünkü küme parantezleri (yani {ve }) meta karakterleri değil, karakterleri ayırır ve bu nedenle her iki tarafta da doğru şekilde ayrıştırmak için boşlukları olması gerekir, ancak meta karakterleri yoktur. Alt kabukların ana ortamı etkilemediğini şimdiye dek bildiğinizi varsayalım, bu nedenle tüm örnek komutların güvenli bir şekilde bir alt kabukta çalıştırılabileceğini varsayalım (bu her durumda tipik değildir), yukarıdaki kodu bu kısaltmayı kısaltabilirsiniz. :

    t=$something
    [ $t == "hi" ]&&(cmd1;cmd2)||[ $t == "bye" ]&&(cmd3;cmd4)||(cmd5;[ $t == "sup" ]&&cmd6)

    Ayrıca, yapamıyorsanız, parantez kullanmak yine de bazılarını küçültebilir. Akılda tutulması gereken bir şey, yalnızca bu tamsayılar için işe yaradığı, bu örneğin amaçları için işe yaramaz kılan (ancak -eqtamsayılar için kullanmaktan çok daha iyidir ) olmasıdır.

  3. Bir şey daha, mümkün olduğunda alıntı yapmaktan kaçının. Yukarıdaki tavsiyeyi kullanarak, daha da küçültebilirsiniz. Örnek:

    t=$something
    [ $t == hi ]&&(cmd1;cmd2)||[ $t == bye ]&&(cmd3;cmd4)||(cmd5;[ $t == sup ]&&cmd6)
  4. Test koşullarında, birkaç istisna dışında olabildiğince çift brakete tek braketleri tercih edin. İki karakteri bedavaya bırakır, ancak bazı durumlarda sağlam değildir (bir Bash uzantısıdır - bir örnek için aşağıya bakınız). Ayrıca, çift yerine single eşit argümanını kullanın. Bırakılması serbest bir karakter.

    [[ $f == b ]]&&: # ... <-- Bad
    [ $f == b ]&&: # ... <-- Better
    [ $f = b ]&&: # ... <-- Best.  word splits and pathname-expands the contents of $f.  Esp. bad if it starts with -

    Bu boşluğu, özellikle boş çıktıyı veya tanımsız bir değişkeni kontrol ederken:

    [[ $f ]]&&:    # double quotes aren't needed inside [[, which can save chars
    [ "$f" = '' ]&&: <-- This is significantly longer
    [ -n "$f" ]&&:

    Bütün teknik bir bu spesifik bir örnek ile iyi olurdu case... in:

    t=$something
    case $t in hi)cmd1;cmd2;;bye)cmd3;cmd4;;*)cmd5;[ $t == sup ]&&cmd6;esac

Yani, bu yazının ahlaki şudur:

  1. Mümkün olduğunca bağlaçlar Kötüye ve her zaman yerine bunları kullanmak if/ if-else/ vb. oluşturur.
  2. Parantezleri mümkün olduğunca parantez kullanın ve alt kabuklarda mümkün olduğu kadar çok segment çalıştırın; çünkü parantezler meta karakterlerdir ve ayrılmış kelimeler değildir.
  3. Fiziksel olarak mümkün olduğunca tırnak kullanmaktan kaçının.
  4. Check out case... in, özellikle string eşlemede epeyce byte tasarruf sağlayabilir.

Not: Burada, bağlamdan bağımsız olarak Bash'te tanınan bir meta-karakterlerin listesi var (ve kelimeleri ayırabilir):

&lt; &gt; ( ) ; & | &lt;space&gt; &lt;tab&gt;

EDIT: İnsan eserinin işaret ettiği gibi, çift parantez testi sadece tamsayılar için çalışır. Ayrıca, dolaylı olarak, ==operatörü çevreleyen boşluk olması gerektiğini keşfettim . Yukarıdaki gönderim düzeltildi.

Ayrıca her bölümün uzunluğunu yeniden hesaplamak için çok tembeldim, bu yüzden onları kolayca kaldırdım. Gerekirse çevrimiçi bir dize uzunluğu hesap makinesi bulmak yeterince kolay olmalı.


Bunu söylediğim için üzgünüm ama orada ciddi hatalarınız var. [ $t=="hi" ]ayrıştırıldığı gibi her zaman 0 olarak değerlendirilir [ -n "STRING" ]. (($t=="hi"))$ t, sayısal olmayan bir değere sahip olduğu sürece, dizeleri aritmetik değerlendirmelerde tam sayılara zorlandığı için her zaman 0 olarak değerlendirilecektir. Bazı test vakaları: pastebin.com/WefDzWbL
manatwork

@ manatwork yakalamak için teşekkürler. Buna göre güncelleyeceğim.
Isiah Meadows

Burada kullanmak casedaha kısa olacaktır. Ayrıca, daha önce bir boşluğa ihtiyacınız yoktur }, ancak sonra yaparsınız {.
nyuszika7h

1
Neden daha =az sağlam olsun ==? =POSIX tarafından zorunlu tutulmuştur, ==değildir.
Dennis,

1
Soru cevap başına bir ipucu soruyor ...
Toby Speight

7

Yerine grep -E, grep -F, grep -r, kullanım egrep, fgrep, rgrep, iki karakter tasarrufu. Daha kısa olanlar kullanımdan kaldırılmıştır ancak iyi çalışırlar.

(Cevap başına bir ipucu istedin!)


1
Çok kötü hiçbir var Pgrepiçin grep -P. Her ne kadar kolayca karışabileceğini görsem de pgrep, süreçleri araştırmak için kullanılır.
nyuszika7h

1
@ nyuszika7h Ben şahsen grep -oçok kullanırım

Alan dahil 3 tane biriktirmez mi?
ckjbgames

7

Bir dizinin Öğe 0'ına yalnızca değişken adıyla erişilebilir, 0 dizini açıkça belirten beş baytlık bir tasarruf:

$ a=(code golf)
$ echo ${a[0]}
code
$ echo $a
code
$ 

7

Bir değişkenin içeriğini bir boru hattındaki bir sonraki işlemin STDIN'sine iletmeniz gerekiyorsa, değişkeni bir boru hattına yansıtmak yaygındır. Fakat aynı şeyi <<< burada bir bash dizesiyle başarabilirsiniz :

$ s="code golf"
$ echo "$s"|cut -b4-6
e g
$ cut -b4-6<<<"$s"
e g
$ 

2
Biz golf yaptığınızdan, s=code\ golf, echo $s|ve <<<$s(göz önünde tutarak bu vb hiçbir tekrarlanan boşluk olmadığından sırf son iki eser).
Dennis

6

Kaçının $( ...command... ), bir karakter kazandıran ve aynı şeyi yapan bir alternatif var:

` ...command... `

9
Bazen $( )iç içe komut değiştirmeleri varsa, gerekli olabilir; Aksi takdirde içten kaçmak zorunda kalacaksın``
Dijital Travma

1
Bunlar teknik olarak farklı şeyler yapıyor, örneğin $()yerine scphedef makine yerine makinemde değişiklik yapmak istediğimde geri tepmek kullanmak zorunda kaldım . Çoğu durumda bunlar özdeştir.
undergroundmonorail

2
@ undergroundmonorail: asla geri tepmenize gerek yok . $()Eğer düzgün bir şekilde alıntı yaparsanız, yapabilecekleri herhangi bir şey yapabilir . (mırıldanan $fakat geriye doğru hareket eden bir şeyden kurtulmak için emrinize ihtiyacınız yoksa ). İçlerindeki şeyleri alıntılamada bazı ince farklılıklar vardır. mywiki.wooledge.org/BashFAQ/082 bazı farklılıkları açıklar. Golf yapmadıkça asla geri tepme kullanmayın.
Peter Cordes

@PeterCordes Orada eminim oldu bir yol ama o anda her şeyi denedik işe yaramadı. Geri tepmeler en iyi çözüm olmasa bile, onlar hakkında bildiğim için memnun oldum, çünkü sahip olduğum tek çözüm buydu. ¯ \ _ (ツ) _ / ¯
undergroundmonorail

@DigitalTrauma Yuvalama örneği: echo `bc <<<"\`date +%s\`-12"`... (Buraya yorumda backtick içeren örnek göndermek zor!)
F. Hauri

6

ifKomutları gruplamak için kullan

Bu özelliği iftamamen ortadan kaldıran uçla karşılaştırıldığında, bu durumun, yalnızca bazı nadir durumlarda, örneğin dönüş değerlerine ihtiyaç duyduğunuzda daha iyi çalışması gerekir if.

Şununla biten bir komut grubunuz varsa if, bunlar:

a&&{ b;if c;then d;else e;fi;}
a&&(b;if c;then d;else e;fi)

Komutları daha önce ifbu koşulda sarabilirsiniz :

a&&if b;c;then d;else e;fi

Veya işleviniz a ile bitiyorsa if:

f(){ a;if b;then c;else d;fi;}

Parantezleri kaldırabilirsiniz:

f()if a;b;then c;else d;fi

1
Üçlü işlecini [test] && $if_true || $elsebu işlevlerde kullanabilir ve bazı baytları kaydedebilirsiniz.
ckjbgames

Ayrıca, çevresinde boşluklara ihtiyacınız yok &&ve||
roblogic

6

(( ... ))Koşullar için aritmetik kullan

Yerini değiştirebilirsiniz:

if [ $i -gt 5 ] ; then
    echo Do something with i greater than 5
fi

tarafından

if((i>5));then
    echo Do something with i greater than 5
fi

(Not: Sonrasında boş yer yoktur if)

ya da

((i>5))&&{
    echo Do something with i greater than 5
}

... ya da sadece bir komut

((i>5))&&echo Echo or do something with i greater than 5

Ayrıca: Değişken ayarını aritmetik yapıda gizle:

((i>5?c=1:0))&&echo Nothing relevant there...
# ...
((c))&&echo Doing something else if i was greater than 5

veya aynı

((c=i>5?c=0,1:0))&&echo Nothing relevant there...
# ...
((c))&&echo Doing something else if i was greater than 5

... i> 5 ise c = 1 (0 değil;)


Sen kullanarak 2 bayt kurtarabilecek [ ]yerine (()).
ckjbgames

@ckjbgames Bundan emin misiniz ?? Hangi bash versiyonunu kullanıyorsunuz?
F. Hauri,

@FHauri Bayt cinsinden yaklaşık olarak aynı olacağını düşünüyorum.
ckjbgames

@ckjbgames [ ]Eğer değişken için dolar işareti gerekir. Aynı veya daha küçük uzunlukta kullanarak nasıl aynı şeyi yapabileceğinizi anlamıyorum [ ].
F. Hauri,

Bonus İpucu: for döngüsünün ilk satırı ile başlarsa, ((...))yeni satır veya boşluk gerekmez. Örneğin for((;10>n++;)){((n%3))&&echo $n;} çevrimiçi deneyin!
primo

6

Sonsuz döngüler için daha kısa bir sözdizimi (bunlar breakveya exitifadelerden kaçılabilir)

for((;;)){ code;}

Bu while true;ve den daha kısa while :;.

Gerekmiyorsa break( exitkaçmanın tek yolu olarak), bunun yerine bir özyinelemeli işlev kullanabilirsiniz.

f(){ code;f;};f

Mola vermeniz gerekiyorsa, ancak çıkmanız gerekmiyor ve döngünün dışındaki herhangi bir değişken değişiklik yapmanıza gerek kalmazsa, işlev gövdesini alt kabukta çalıştıran parantez içinde özyinelemeli bir işlev kullanabilirsiniz .

f()(code;f);f

6

Bir satır fordöngüler

Bir aralık genişletme ile birleştirilen bir aritmetik ifade, aralıktaki her öğe için değerlendirilir. Örneğin, aşağıdakiler:

: $[expression]{0..9}

expression10 kez değerlendirecek .

Bu genellikle eşdeğer fordöngüden önemli ölçüde daha kısadır :

for((;10>n++;expression with n)){ :;}
: $[expression with ++n]{0..9}

Komut hata bulmazsanız, inital'i kaldırabilirsiniz :. 10'dan büyük yinelemeler için karakter aralıklarını da kullanabilirsiniz, örneğin {A..z}58 kez yinelenir .

Pratik bir örnek olarak, aşağıdakilerden her ikisi de her biri kendi satırında bulunan ilk 50 üçgen sayıyı üretir:

for((;50>d++;)){ echo $[n+=d];} # 31 bytes
printf %d\\n $[n+=++d]{A..r}    # 28 bytes

ayrıca geriye doğru yineleyebilirsiniz:for((;0<i--;)){ f;}
roblogic

5

Argümanlar üzerinden döngü

Belirtildiği gibi bir “foo bar ...” kısmı olmadan döngü “için” Bash , in "$@;"içinde for x in "$@;"gereksiz olduğunu.

Kimden help for:

for: for NAME [in WORDS ... ] ; do COMMANDS; done
    Execute commands for each member in a list.

    The `for' loop executes a sequence of commands for each member in a
    list of items.  If `in WORDS ...;' is not present, then `in "$@"' is
    assumed.  For each element in WORDS, NAME is set to that element, and
    the COMMANDS are executed.

    Exit Status:
    Returns the status of the last command executed.

Örneğin, konumsal argümanlar verilen tüm sayıları bir Bash betiğine veya bir işleve kare yapmak istiyorsak, bunu yapabiliriz.

for n;{ echo $[n*n];}

Çevrimiçi deneyin!


5

Kedi alternatif

Bir dosyayı okumaya ve başka bir şeyde kullanmaya çalıştığınızı söyleyin. Yapabileceğin şey:

echo foo `cat bar`

İçeriği ise baroldu foobar, bu basacaktır foo foobar.

Ancak, bu yöntemi kullanıyorsanız, 3 bayt kazandıran bir alternatif var:

echo foo `<bar`

1
<barKendi başına çalışmamasının, ancak onu geri tepmelere yerleştirmenin bir nedeni var mı ?
Kritixi Lithos

@Cowsquack Evet. <Bir komuta dosya koyar, ancak bu durumda nedeniyle bir cilvesi standart çıkışa içine koyar. Backticks bunu birlikte değerlendirir.
Okx

Standart girdilerden başka bir okuma yapmanın daha kısa bir yolu var mı `cat`?
Joel

4

Kullanım [yerine [[ve testmümkün olduğunda

Örnek:

[ -n $x ]


Kullanım =yerine ==karşılaştırma için

Örnek:

[ $x = y ]

Eğer unutmayın gerekir Eşittir işareti etrafında boşluk varsa veya başka işe yaramaz. Aynısı ==testlerime dayanmak için de geçerlidir .


3
[Vs [[gerekli tırnak miktarına bağlı olabilir: pastebin.com/UPAGWbDQ
manatwork

@ manatwork Bu iyi bir nokta.
nyuszika7h

1
Genel kural: [... ]== /bin/testama [[... ]]! = /bin/testVe bir tercih asla [... ]üzerinde [[... ]]codegolf dışına
kedi

4

Alternatifleri head

lineüç bayttan daha kısa head -1, ancak kullanımdan kaldırılıyor .

sed qiki bayttan daha kısa head -1.

sed 9qbir bayttan daha kısa head -9.


1
Her ne kadar mahkum , biz hala bir süre kullanabilirsiniz linegelen util-linux tek bir satır okumak için paketin.
Manatwork

4

tr -cd daha kısa grep -o

Örneğin, boşluk saymanız gerekiyorsa grep -o <char>(yalnızca eşleşenleri yazdırın) 10 bayt verirken tr -cd <char>(silme tamamlayıcısı <char>) 9 verir.

# 16 bytes
grep -o \ |wc -l
# 15 bytes
tr -cd \ |wc -c

( kaynak )

İkisinin de biraz farklı çıktılar verdiğine dikkat edin. aynı satırda hepsini grep -overirken satırdan ayrılan sonuçları döndürür tr -cd, bu nedenle trher zaman uygun olmayabilir.


4

Kısaltılmış dosya isimleri

Son zamanlardaki bir zorlukla dosyayı okumaya çalışıyordum /sys/class/power_supply/BAT1/capacity, ancak bu /*/*/*/*/capac*yformatta başka hiçbir dosya bulunmadığı için bu kısaltılabilir .

Örneğin foo/, dosyaları içeren bir diziniz foo, bar, foobar, barfoovarsa ve dosyaya başvurmak foo/barfooistiyorsanız, foo/barf*bir bayt kaydetmek için kullanabilirsiniz .

*"Bir şey" temsil eder ve regex eşdeğerdir .*.


3

:Komuta yerine bir boru kullanın /dev/null. :Yerleşik tüm giriş yiyeceklerdir.


2
Hayır, çoğu durumda programı SIGPIPE ile kilitleyecektir. echo a|tee /dev/stderr|:hiçbir şey basmayacak.
jimmy23013

Bir yarış var: echo a|tee /dev/stderr|:bilgisayarıma baskı yaptım, ancak başka bir yerde SIGPIPE ilk önce tee öldürebilir. Sürümüne bağlı olabilir tee.
saat

Evet, bu bir SIGPIPE problemi: tee >(:) < <(seq 1 10)çalışacak, ama tee /dev/stderr | :olmayacak. a() { :;};tee /dev/stderr < <(seq 1 10)| aHiçbir şey bile basmıyorsun.
F. Hauri,

@ user16402 - benim görüşüme göre bir fccing ismine sahip olmalısın ... her neyse, :içsel hiç yemez ... eğer kolona girdiyi kabul edersen, bir boruyu dışarıya aktarabilirsin ... ama bir yönlendirme yapabilirsin iki nokta üst üste, ya da onunla bir süreç ... :| while i>&$(($??!$?:${#?})) command shit; do [ -s testitsoutput ]; doneya da sözde öneri geçerli olsa da ... aynı zamanda, sen de benim kadar hırçın olduğunun farkında mısın? ... Hiç önlemek maliyeti< <(psycho shit i can alias to crazy math eat your world; okay? anyway, ksh93 has a separate but equal composite char placement)
mikeserv

3

splitgirişi ( Nher biri kesik, ancak hiç kimsenin umrunda değil) girişi her biri satır bölümlerine ayırmak için sözdizimi vardır : yerine örneğin split -lNkullanabilirsiniz .split -Nsplit -9


3

Testleri genişlet

Temel olarak, kabuk bir tür makro dili ya da en azından bir melez ya da bir türdür. Her komut satırı temel olarak iki bölüme ayrılabilir: ayrıştırma / giriş bölümü ve genişletme / çıkış bölümü.

İlk bölüm, çoğu insanın odaklandığı şeydir, çünkü en basit olanı: ne elde ettiğinizi görürsünüz. İkinci kısım, birçok insanın çok iyi anlamaya çalışmaktan bile kaçınılmasıdır ve insanların neden böyle şeylerin evalkötü olduğunu söylediğini ve her zaman açılımlarınızı dile getirdiğini söyler - insanlar ilk bölümün sonucunun birincisine eşit olmasını ister. Sorun değil - ama gereksiz yere uzun kod dalları ve tonlarca yabancı testlere yol açıyor.

Genişlemeler kendi kendini test ediyor . ${param[[:]#%+-=?]word}Formlar, bir parametrenin içeriğini doğrulamak için fazlasıyla yeterli olan iç içe girebilmesi ve herkes için değerlendirilmesi etrafında dayanır NUL - çoğu insan zaten testlerin beklediğiniz olduğu. +döngüler içinde özellikle kullanışlı olabilir:

r()while IFS= read -r r&&"${r:+set}" -- "$@" "${r:=$*}";do :;done 2>&-

IFS=x
printf %s\\n some lines\ of input here '' some more|{ r;echo "$r"; }

somexlines ofxinputxhere

... readboş olmayan satırları çekerken "${r:+set}"genişler "set"ve konumlar $reklenir. Boş bir satır olduğunda Fakat read, $rboş ve "${r:+set}"genişler ""- geçersiz komuttur. Komut satırı genişletilir çünkü önce"" boş komut aranır, "${r:=$*}"ilk byte üzerinde birleştirilmiş positionals tüm değerlerini alır $IFSda. bir sonraki giriş paragrafını elde etmek için farklı bir değer r()olan |{bileşik komutunda tekrar çağırılabilir , çünkü bir kabuğun girilen bir sonraki satırın ötesinde tamponlaması yasaktır.;}$IFSread\n


3

Halkaları kısaltmak için kuyruk özyineleme kullanın:

Bunlar davranışta eşdeğerdir (muhtemelen bellek / PID kullanımında olmasa da):

while :;do body; done
f()(body;f);f
body;exec $0
body;$0

Ve bunlar kabaca eşdeğerdir:

while condition; do body; done
f()(body;condition&&f);f
body;condition&&exec $0
body;condition&&$0

(teknik olarak son üç vücut her zaman en az bir kere yürütülür)

Kullanmak $0, komut dosyanızın bash istemine yapıştırılmamış bir dosyada olmasını gerektirir.

Sonunda yığınız taşabilir, ancak bazı baytları kaydedersiniz.


3

Bazen, exprnormalin yerine basit bir aritmetik ifadenin sonucunu görüntülemek için yerleşimi kullanmak daha kısadır echo $[ ]. Örneğin:

expr $1 % 2

bir bayt şundan kısa:

echo $[$1%2]

2

Bir çıktı satırı üretmek pwdyerine kullanınecho

Stdout'a bir çizgi koymanız mı gerekiyor, ancak içeriği umursamıyor ve cevabınızı kabuk yerleşiklerine sınırlamak mı istiyorsunuz? pwdondan daha kısa bir bayttır echo.


2

Dizeleri yazdırırken tırnaklar atlanabilir.

echo "example"
echo example

SM-T335 LTE, Android 5.1.1’de çıkış:

u0_a177@milletlte:/ $ echo "example"
example
u0_a177@milletlte:/ $ echo example
example

2

Sürekli olmayan dizi öğeleri atarken, sürekli parçaların art arda gelen dizinlerini atlayabilirsiniz:

bash-4.4$ a=([1]=1 [2]=2 [3]=3 [21]=1 [22]=2 [23]=3 [31]=1)

bash-4.4$ b=([1]=1 2 3 [21]=1 2 3 [31]=1)

Sonuç aynı:

bash-4.4$ declare -p a b
declare -a a=([1]="1" [2]="2" [3]="3" [21]="1" [22]="2" [23]="3" [31]="1")
declare -a b=([1]="1" [2]="2" [3]="3" [21]="1" [22]="2" [23]="3" [31]="1")

Göre man bash:

Diziler, name = = (değer 1 ... değer n ) biçimindeki bileşik atamaları kullanmak için atanır , burada her değer [ subscript ] = string biçimindedir . Dizinlenmiş dizi atamaları dizeden başka bir şey gerektirmez . Dizinlenmiş dizilere atanırken, isteğe bağlı parantezler ve alt simge sağlanmışsa, bu dizin; Aksi halde, atanan öğenin dizini, deyim artı birinin atadığı son dizindir.


Eklemek yararlı: başlatılmamış öğeler aritmetik genişlemelerde 0'a, diğer genişlemelerde ise "" olacaktır.
Dijital Travma,

2

Bir dizedeki ilk sözcüğü yazdır

Dize değişkendeyse ave escape ve format karakterleri ( \ve %) içermiyorsa , şunu kullanın:

printf $a

Ancak, sonucu yazdırma yerine bir değişkene kaydetmek gerekirse, aşağıdaki koddan daha uzun olacaktır:

x=($a)
$x

1

1 forkomutu ile 2 embed loop yapıyor :

for ((l=i=0;l<=99;i=i>98?l++,0:++i)) ;do
    printf "I: %2d, L: %2d\n" $i $l
done |
    tee >(wc) | (head -n4;echo ...;tail -n 5)
I:  0, L:  0
I:  1, L:  0
I:  2, L:  0
I:  3, L:  0
...
I: 96, L: 99
I: 97, L: 99
I: 98, L: 99
I: 99, L: 99
  10000   40000  130000

1

Alıntılanan dizeleri Ata ve Yazdır

Bir değişkene alıntı bir dize atamak ve ardından bu değişkenin değerini yazdırmak istiyorsanız, bunu yapmanın normal yolu şöyle olacaktır:

a="Programming Puzzles & Code Golf";echo $a

Daha aönce ayarlanmamışsa, bu kısaltılabilir:

echo ${a=Programming Puzzles & Code Golf}

Daha aönce ayarlandıysa, bunun yerine bu kullanılmalıdır:

echo ${a+Programming Puzzles & Code Golf}

Bunun yalnızca, dizenin tırnak gerektirmesi durumunda kullanışlıdır (örneğin, boşluklar içerir). Tırnak olmadan a=123;echo $a, sadece kısa.


${a+foo}ayarlanmadı a.
GammaFunction
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.