Subshell kullanmadan shell komutu değiştirme işlemini gerçekleştirmek mümkün müdür?


11

Bir alt kabuk kullanmadan komut değiştirme için çağrılan bir senaryo var. Ben böyle bir yapı var:

pushd $(mktemp -d)

Şimdi çıkmak ve geçici dizinde tek seferde kaldırmak istiyorum:

rmdir $(popd)

Ancak bu, çalışmayan popddizini (yeni, şimdi geçerli olan dizini döndürür) döndürmediği ve ayrıca bir alt kabukta gerçekleştirildiği için çalışmaz.

Gibi bir şey

dirs -l -1 ; popd &> /dev/null

açılan dizini döndürür ancak şu şekilde kullanılamaz:

rmdir $(dirs -l -1 ; popd &> /dev/null)

çünkü popdirade sadece alt kabuğu etkiler. Ne denir bunu yapmak için yeteneği:

rmdir { dirs -l -1 ; popd &> /dev/null; }

ancak bu geçersiz sözdizimi. Bu etkiyi elde etmek mümkün müdür?

(Not: Geçici dizini bir değişkene kaydedebileceğimi biliyorum; Bunu yapma ve süreçte yeni bir şey öğrenme ihtiyacından kaçınmaya çalışıyordum!)


1
Dizini bir değişkene kaydederdim; bu şekilde bir trapişleyici, işlem bir sinyalle delinirse dizini temizleyebilir.
thrig

Cevap hayır .
h0tw1r3

fishKomut ikamesinin eşdeğeri gibi görünür (), dış kabuğun klasörünü değiştirir. Genellikle sinir bozucu, ancak bu gibi durumlarda işe yarar, eminim.
trysis

Yanıtlar:


10

Sorunuzun başlığının seçimi biraz kafa karıştırıcı.

pushd/ popd, ve cshtarafından kopyalanan bir özellik , hatırlanan dizin yığınını yönetmenin bir yoludur.bashzsh

pushd /some/dir

geçerli çalışma dizinini bir yığının üzerine iter ve sonra geçerli çalışma dizinini değiştirir (ve sonra yazdırır ve ardından /some/diro yığının içeriğini izler (boşlukla ayrılır).

popd

yığının içeriğini yazdırır (yine boşlukla ayrılır) ve ardından yığının üst öğesine değişir ve yığından çıkar.

(ayrıca bazı dizinlerin orada ~/xya da ~user/xgösterimleriyle temsil edileceğine dikkat edin ).

Yığında şu anda /ave varsa /b, geçerli dizin /hereve çalıştırıyorsanız:

 pushd /tmp/whatever
 popd

pushdyazdırılacak /tmp/whatever /here /a /bve popdçıktı /here /a /balınmayacak /tmp/whatever. Bu komut yerine koyma kullanmaktan bağımsızdır. popdönceki dizinin yolunu elde etmek için kullanılamaz ve genel olarak çıktısı sonradan işlenemez ( bu dizin yığının öğelerine erişmek için olsa da bazı kabukların dizisine $dirstackveya $DIRSTACKdizisine bakın )

Belki siz istersiniz:

pushd "$(mktemp -d)" &&
popd &&
rmdir "$OLDPWD"

Veya

cd "$(mktemp -d)" &&
cd - &&
rmdir "$OLDPWD"

Yine de, ben:

tmpdir=$(mktemp -d) || exit
(
  cd "$tmpdir" || exit # in a subshell 
  # do what you have to do in that tmpdir
)
rmdir "$tmpdir"

Her durumda, bir alt kabukta pushd "$(mktemp -d)"çalışmaz pushd. Eğer öyleyse, çalışma dizinini değiştiremedi. Bu mktempbir alt kabukta çalışır. Ayrı bir komut olduğundan, ayrı bir işlemde çalışması gerekir. Çıktısını bir boruya yazar ve kabuk işlemi bunu borunun diğer ucunda okur.

ksh93, komut yerleşik olduğunda ayrı işlemden kaçınabilir, ancak orada bile, bu süre normal olarak çatallamanın sağladığı ayrı ortama güvenmek yerine taklit edilen bir alt kabuk (farklı bir çalışma ortamı). Örneğin, ksh93, a=0; echo "$(a=1; echo test)"; echo "$a", hiçbir çatal hala katılan, ancak echo "$a"çıkışları 0.

Eğer çıktısını depolamak istiyorsanız Burada, mktempsen bunu geçerken aynı zamanda bir değişkende, pushdile, zshyapmanız olabilir:

pushd ${tmpdir::="$(mktemp -d)"}

Bourne benzeri diğer mermilerle:

unset tmpdir
pushd "${tmpdir=$(mktemp -d)}"

Ya da çıktıyı $(mktemp -d)bir değişkende açıkça saklamaksızın birkaç kez kullanmak için zshanonim işlevleri kullanabilirsiniz :

(){pushd ${1?} && cd - && rmdir $1} "$(mktemp -d)"

Anladığınız pushdve popdtanımladığınız gibi çalıştığınız ve onların komuta ikamesinden bağımsız olduklarını - orada karışıklık yok! Ancak, kendi probleminizle açığa vurarak cevap verdiniz $OLDPWD. Yapabilirim popd; rmdir $OLDPWD. Sorunumun cevabı budur - diğer her şey düşündüğümü doğrular. Komut ikamesi bunu çözmenin bir yolu gibi görünüyor, ancak alt kabuk yüzünden değil ve alt kabuk olmadan komut ikamesi yapamazsınız, bu yüzden OLDPWD'yi açığa çıkardığınız için teşekkürler - tam da ihtiyacım olan bu!
starfry

@starfry, bir alt kabukta çalışmasına rmdir $(popd)neden olur popd, bu da geçerli dizini değiştirmeyeceği anlamına gelir, ancak bir alt kabukta çalıştırılmasa bile, çıktısı popdgeçici dizin olmayacak, boşlukla ayrılmış bir liste olacaktır Bu geçici dizini içermeyen dizinler. Burada kafan karıştığını söylüyorum.
Stéphane Chazelas

ama sorumda şunu söylediğimi sanıyordum: "popd, açılan dizini döndürmez (yeni, şimdi geçerli olan dizini döndürür) ve ayrıca bir alt kabukta gerçekleştirildiği için." Kuşkusuz bir liste döndürür, ancak listedeki ilk listeden bahsettiğim listedir.
starfry

@starfry, tamam üzgünüm. Diyelim ki, soru başlığıyla karıştırılan benim oldum ve gerisini yeterince dikkatli okumadım.
Stéphane Chazelas

cevabınız hala iyiydi ve beni doğru yöne çekti. Kabuk değişkenini hiç bilmiyordum OLDPWD. Bir gün man bashbaştan sona okumayı hatırlamalıyım !
starfry

2

Ayrılmadan önce dizinin bağlantısını kaldırabilirsiniz:

rmdir "$(pwd -P)" && popd

veya

rmdir "$(pwd -P)" && cd ..   # yes, .. is still usable

ancak dikkat edin pushdve popdgerçekten komut dosyaları için değil, etkileşimli kabuklar için araçlar (bu yüzden çok konuşkanlar; başarılı olduklarında gerçek komut dosyası komutları sessizdir).


0

Bash olarak, dirsPushd / Popd yöntemiyle hatırlanan dizinlerin listesini sağlamak.

Ayrıca, dirs -1listede bulunan son dizini yazdırır.

Bu nedenle, önceden yürüterek oluşturulan dizini kaldırmak için şunu pushd $(mktmp -d)kullanın:

rmdir $(dirs -1)

Ve sonra, popdönceden kaldırılmış dizin listeden:

popd > /dev/null

Hepsi bir satırda:

rmdir $(dirs -1); popd > /dev/null

Ve seçeneği (-l) eklemekten kaçının ~/xveya ~user/xgösterim:

rmdir $(dirs -l -1); popd > /dev/null

Bu, istediğiniz hatta oldukça benzer.
Dışında &>herhangi bir hata raporlama tarafından gizlemek gibi kullanmak olmaz popd.

Not: Dizin o noktada rmdirolduğu gibi kalır pwd. Ve aslında popdkomuttan sonra bağlantısı kaldırılacaktır (kalan bağlantı kullanılmaz).


"OLDPWD" değişkenini destekleyen kabuklar için (en bourne benzeri kabuklar: ksh, bash, zsh have $OLDPWD) bir seçenek vardır . Ksh'ın varsayılan olarak dirs, pod, pushd uygulamadığına dikkat etmek ilginçtir (lksh, dash ve diğerlerinde de popd yoktur, bu nedenle burada kullanılamazlar):

popd && rmdir "$OLDPWD"

Veya daha deyimsel (yukarıdaki kabuklarla aynı liste):

popd && rmdir ~-

Buradaki sorun ve çözmeye çalıştığım şey, bunu rmdiryaparken geçerli dizinde olamayacağınızdır. Yapmadan popdönce etkilemeniz gerekir , rmdirancak neyin kaldırılacağını bilmeniz gerekir ve popdbunu söylemez. Ben de senin gibi düşündüm dirs -l -1ama cevabın aslında kullanacağını keşfettim $OLDPWD.
starfry

Ben en kısa cevap kullanımına olduğuna inanıyoruz @starfry: popd && rmdir ~-.

@starfry Geçerli dizini, boş olması koşuluyla (silmeye zorlamadan) gerçekten kaldırabilirsiniz. Tamam bile diyebilirsin rmdir "$PWD". Ayrıca, geçerli dizin tarafından oluşturulan mktmp -d( pushd $(mktemp -d)önceden çalıştırılmışsa) ve pushdpwd'yi taşıyan dizin olmalıdır . Yani, evet, popd sonra pushd ve önce , oluşturulan dizin saklanır $(dirs -1), herhangi bir sorun göremiyorum.
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.