Dizin adlarında boşluk olduğunda bash değişkenlerini kullanarak dizine gitmek çalışmaz


11

Diyelim ki aşağıdaki komutu bir değişkende saklamak istiyorum

cd "/cygdrive/c/Program Files/"

Ben de bunu yapıyorum

dir="cd \"/cygdrive/c/Program Files/\""

Bu, Program Files dizinine gitmek için komutu saklamalıdır, bu yüzden $ dir yazdığımda beni bu dizine götürür. Tekliflerin doğru bir şekilde kaçıldığını kontrol etmek için

echo $dir

hangisi bana verir

cd "/cygdrive/c/Program Files/"

Yani her şey iyi çalışıyor olmalı. Ancak, yazdığımda,

$dir

alırım

bash: cd: "/cygdrive/c/Program: No such file or directory

Neyi yanlış yapıyorum? Cygwin kullanıyorum, ancak bu sorunun genel olarak bash için geçerli olduğunu varsayıyorum.


Dizin adının çevresindeki tırnak işaretlerini kaldırmayı deneyin ve bunun yerine boşlukla ters eğik çizgiden çıkın.
Mike Fitzpatrick

Yanıtlar:


8

Kısa cevap: bkz. BashFAQ # 050 ("Bir değişkene komut koymaya çalışıyorum, ancak karmaşık durumlar her zaman başarısız oluyor!").

Uzun cevap: bash bir komutu ayrıştırdığında, değişkenleri değiştirmeden önce tırnakları ayrıştırır; asla geri gitmez ve değişkenlerin değerlerindeki tırnak işaretlerini yeniden ayrıştırır, böylece yararlı bir şey yapmamaktan kurtulamazlar. Komutu kontrol etmek için echo komutunu kullanmak tamamen yanıltıcıdır çünkü ayrıştırıldıktan sonra komutu gösterir ; gerçekte ne yürütüldüğünü görmek istiyorsanız, ya set -xkabuk yürütme komutlarını yürütülürken kullanın ya da printf "%q " $dir; echodüz eko yerine kullanın .

Karmaşık bir komut saklamak istiyorsanız (örneğin, "sözcüklerde" boşluk veya diğer özel karakterlere sahip bir komut), basit bir metin değişkeni yerine onu bir diziye koymanız ve ardından "$ {deyimiyle genişletmeniz gerekir. dizi [@]} ", şöyle:

dir=(cd "/cygdrive/c/Program Files/")
"${dir[@]}"

Şimdi, eğer amacı yazması kolay bir stenografi yapmaksa, bu açıkça bir yol değildir. Bunun yerine kabuk takma adı veya işlevi kullanın:

alias dir='cd "/cygdrive/c/Program Files/"'
dir

veya

dir() { cd "/cygdrive/c/Program Files/"; }
dir

7

Bash genişlediğinde $dir, yalnızca sözcük bölme ve globbing gerçekleştirir. Kelime bölme üç kelime üretir: cd, "/cygdrive/c/Programve Files/". Sonra yürütmek için komut cdiki argüman ile; cdsadece "/cygdrive/c/Programvar olan bir dizin olmayan ilk argümanına bakar .

Bir değişkenin içeriği üzerinde tam kabuk değerlendirmesi yapmak istiyorsanız, şunu kullanın eval:

eval "$dir"

Etrafında çift tırnak işareti kullanmanız gerektiğini unutmayın $dir, aksi takdirde kelime bölme işlemi gerçekleştirilir, daha sonra evalargümanlarını boşluklarla birleştirirsiniz. Bu burada işe yarayabilir, ancak genel olarak kötü olur (örneğin, bir dosya adında art arda iki boşluk varsa).

Ancak, bir dize yürütmek istediğiniz kabuk komutunu depolamanın doğru yolu değildir. Alışılmadık bir gereksiniminiz yoksa, bunun yerine bir işlev kullanmalısınız:

dir () {
  cd "/cygdrive/c/Program Files/"
}

Eğer gerçekten yazarak ilgilenen varsa $dirbelirli bir dizine anahtara ve bu bash 4 beri sadece basit bir örnek değildir, koyun shopt -s autocdsenin içinde .bashrcve seti

dir="/cygdrive/c/Program Files/"

bundan sonra bu dizine geçmek için sadece "/cygdrive/c/Program Files/"veya "$dir"kabuk komut istemine yazabilirsiniz . Hala çift tırnaklara ihtiyacınız var $dir; Eğer beğenmediyseniz, bash yerine zsh kullanın.


6

Komutları değişkenlerde saklamak genellikle iyi bir fikir değildir. Fonksiyonlar ve takma adlar bunun içindir.

Ziyade

dir="cd \"/cygdrive/c/Program Files/\""

bunlardan birini deneyin:

dir="/cygdrive/c/Program Files"
...
cd "$dir"

veya

dir() { cd "/cygdrive/c/Program Files"; }
dir

veya

alias dir='cd "/tmp/Program Files"'
...
dir

İlk form, dizinin adını bir değişkende saklamak, biraz daha yazmak anlamına gelir, ancak yaptığınız komutu yürüttüğünüzde daha açıktır cd. İkincisi, başarmaya çalıştığınız şeye en yakın olanıdır. (Diğer adları bash'de çok kullanmıyorum; aslında işlevler üzerinde ne gibi avantajları olduğundan emin değilim.)

DÜZENLE :

Ve dirmuhtemelen bir takma ad veya işlev için kötü bir addır, çünkü bu adda mevcut bir komut vardır (temel olarak ls, en azından GNU coreutils'iniz varsa, bunun bir sürümüdür ).


için upvoteStoring commands in variables is generally not a good idea. That's what functions and aliases are for.
Rob

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.