Alıntılanan bir değişkeni, boşsa nasıl hiçbir değere genişletebilirim?


21

Diyelim ki bir senaryom var:

some-command "$var1" "$var2" ...

Ve var1boş durumda, yerine boş dize yerine hiçbir şey ile değiştirilmesini tercih, böylece yürütülen komut:

some-command "$var2" ...

ve yok:

some-command '' "$var2" ...

Değişkeni test etmekten ve koşullu olarak dahil etmekten daha basit bir yolu var mı?

if [ -n "$1" ]; then
    some-command "$var1" "$var2" ...
    # or some variant using arrays to build the command
    # args+=("$var1")
else
    some-command "$var2" ...
fi

Bash, zsh veya benzerlerinde hiçbir şeye genişleyemeyen bir parametre ikamesi var mı? Hala argümanların geri kalanında globbing kullanmak isteyebilirsiniz, bu yüzden devre dışı bırakmak ve değişken unquoting bir seçenek değildir.


Bunu daha önce gördüğümü ve muhtemelen kullandığımı biliyordum, ama aramak zor oldu. Michael sözdizimini gösterdiğine göre, nerede ilk gördüğümü yeterince hatırladım : unix.stackexchange.com/a/269549/70524 , unix.stackexchange.com/q/68484/70524
muru

Bunun bir tür parametre ikamesi olduğunu biliyorsanız, neden sayfanın parametre genişletme bölümüne manbakmadınız? (-;
Philippos

1
@Philippos O zaman ne olduğunu bilmiyordum, sadece daha önce gördüğüm ya da kullandığım. Bilinen bilenler ve bilinmeyen bilenler. :(
muru

1
Sorunun kendisindeki bağımsız değişkenleri tutmak için bir dizi kullandığından bahsetmek için ekstra çerez noktaları.
ilkkachu

Yanıtlar:


29

Posix uyumlu kabuklar ve Bash'in özellikleri ${parameter:+word} :

Eğer parametre ayarlanmadan ya da boş, boş ikame edilir; aksi takdirde kelimenin genişletilmesi (veya sözcük atlanırsa boş bir dize ) değiştirilir.

Böylece şunları yapabilirsiniz:

${var1:+"$var1"}

ve var var1kontrol edilmeli ve "$var1"bunun oturmaya ve boş olmayan eğer (sıradan çift alıntı kurallarına) kullanılmalıdır. Aksi takdirde hiçbir şeye genişlemez. Burada sadece kısmın alıntılandığına dikkat edin, her şeyin değil.

Aynı şey zsh'de de çalışır. Değişkeni tekrarlamanız gerekir, bu yüzden ideal değildir, ancak tam olarak istediğiniz gibi çalışır.

Boş bırak değişkeninin boş bir bağımsız değişkene genişlemesini istiyorsanız ${var1+"$var1"}bunun yerine kullanın.


1
Benim için yeterince iyi. Yani, bunda, her şey alıntılanmaz, sadece wordkısımdır.
muru

1
Sorunun "bash, zsh veya benzeri" (ve Soru-Cevap arşivi) için sorulduğu gibi, bunun bir posix özelliği olduğunu yansıtacak şekilde düzenledim. Hatta, yorumumdan sonra soruya bir / bash etiketi eklerseniz. (-;
Philippos

2
I arasındaki fark düzenleme özgürlük aldı :+ve +.
ilkkachu

POSIX uyumlu bir çözüm için çok teşekkürler! Ben potansiyel chokepoint scriptleri için sh/ kullanmaya çalışıyorum dash, bu yüzden birisi Bash başvurmadan bir şey nasıl mümkün olduğunu gösterdiğinde her zaman takdir ediyorum.
JamesTheAwesomeDude

Ben ters etki arıyordu (null olarak başlarsa başka bir şeye genişletmek). Bu mantığın + işaretini şu şekilde değiştirerek tersine çevrilebileceği ortaya çıktı: $ {empty_var: -replacement}
Alex Jansen

5

Yani ne zshsen tırnak ihmal varsayılan olarak yapar:

some-command $var1 $var2

Aslında, parametre genişletmesi etrafında zsh cinsinden tırnak işaretine ihtiyacınızın tek nedeni, parametre genişletmelerini teklif zshetmediğinizde diğer kabukları etkileyen diğer sorunlara sahip olmadığından (örtük bölünme + glob) .

Aynı şeyi bölmeyi ve yuvarlamayı devre dışı bırakırsanız POSIX benzeri kabuklarla da yapabilirsiniz:

(IFS=; set -o noglob; some-command $var1 $var2)

Şimdi, değişkeniniz 0 veya 1 değerine sahipse, bir dizi olmalı ve bir skaler değişken olmalı ve şunu kullanmalıdır:

some-command "${var1[@]}" "${var2[@]}"

Ve kullanım var1=(value)sırasında var1, bir değeri içeren etmektir var1=('')bunun bir boş değer içeren olduğunda ve var1=()bunun içerdiği olduğunda hiçbir değer.


0

Ben -nkuru çalışır geçiş yapmak için veya olmadan komutu başlatan bir bash komut dosyasında rsync kullanarak bu koştu . Rsync ve bir dizi gnu komutunun ''geçerli bir ilk argüman olarak alındığı ve orada olmadığından farklı hareket ettiği ortaya çıkıyor.

Boş parametreler neredeyse tamamen görünmez olduğu için bu hata ayıklamak oldukça zaman aldı.

Rsync listesindeki biri kodlamamı büyük ölçüde basitleştirirken bana bu problemden kaçınmanın bir yolunu gösterdi . Doğru anlıyorsam, bu @ Stéphane Chazelas'ın son önerisindeki bir varyasyon.

Komut bağımsız değişkenlerinizi birkaç ayrı değişkende oluşturun. Bunlar, soruna uyan herhangi bir sırayla veya mantıkla ayarlanabilir.

Daha sonra, sonunda, her şeyi uygun yerde bir dizi oluşturmak için değişkenleri kullanın ve bunu gerçek komutun argümanları olarak kullanın.

Bu şekilde komut, bağımsız değişkenlerin her bir varyasyonu için tekrarlanmak yerine kodun yalnızca bir yerinde verilir.

Boş olan tüm değişkenler bu yöntem kullanılarak kaybolur.

Eval kullanmanın son derece kaşlarını çattığını biliyorum. Tüm detayları hatırlamıyorum, ancak bu şekilde çalışacak şeyleri elde etmek için ona ihtiyacım var gibiydi - gömülü beyaz boşluklu parametrelerin işlenmesi ile ilgili bir şey.

Örnek:

dry_run=''
if [[ it is a test run ]]
then
  dry_run='-n'
fi
...
rsync_options=(
  ${dry_run}
  -avushi
  ${delete}
  ${excludes}
  --stats
  --progress
)
...
eval rsync "${rsync_options[@]}" ...

Bu, soruda tarif ettiğim şeyi yapmanın daha kötü bir yoludur (şartlı olarak bir dizi argüman oluşturmak). Değişkenleri boş bırakarak, kendinizi hangi sorunlara açık bıraktığınızı kim bilebilir?
muru

@muru Haklısın, ama yine de böyle bir şeye ihtiyacım var. Diğer cevaplardaki teknikleri kullanarak nasıl düzeltileceğini tam olarak göremiyorum. Her şeyi bir araya getiren bir kod parçasının doğru şekilde yapıldığını görmek harika olurdu. Stephane'ın son seçeneğiyle oynayacağım, çünkü bu istediğimi yapabilir.
Joe


Sadece buna geri döndüm. Örnek için teşekkürler. Mantıklı. Onunla çalışacağım.
Joe

Burada benzer bir kullanım durumu var, ama böyle bir şey yapabilir: if ["$ dry" == "true"]; sonra kuru = "- n"; fi ... eğer değişken dry doğruysa, -n olmasını sağlarsınız ve rsync komutunuzu her zamanki gibi inşa edersiniz ve şöyle yaparsınız: rsync $ {dry1: + "$ dry1"} ... boşsa hiçbir şey olmayacak, aksi halde
emrinizde
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.