Mevcut kabukta bir komutun çıktısı nasıl çalıştırılır?


92

İçeriği bir dosyadan alacak ve mevcut kabukta çalıştıracak source(aka .) yardımcı programından haberdarım .

Şimdi, bazı metni kabuk komutlarına dönüştürüyorum ve ardından aşağıdaki gibi çalıştırıyorum:

$ ls | sed ... | sh

lssadece rastgele bir örnek, orijinal metin herhangi bir şey olabilir. sedayrıca, metni dönüştürmek için sadece bir örnek. İşin ilginç yanı sh. Ne yaparsam alayım shve onu çalıştırır.

Benim sorunum, bu yeni bir alt kabuk başlatmak anlamına geliyor. Komutların mevcut kabuğumda çalışmasını tercih ederim. source some-fileKomutlar bir metin dosyasında olsaydı, yapabileceğim gibi .

Bir geçici dosya oluşturmak istemiyorum çünkü kirli hissediyor.

Alternatif olarak, alt kabuğumu mevcut kabuğumla tamamen aynı özelliklerle başlatmak istiyorum.

Güncelleme

Tamam, backtick kullanan çözümler kesinlikle işe yarıyor, ancak genellikle çıktıyı kontrol ederken ve değiştirirken bunu yapmam gerekiyor, bu yüzden sonucu bir şeye yönlendirmenin bir yolu olsaydı daha çok tercih ederim.

üzücü güncelleme

Ah, bu /dev/stdinşey çok güzel görünüyordu ama daha karmaşık bir durumda işe yaramadı.

Yani bende şu var:

find . -type f -iname '*.doc' | ack -v '\.doc$' | perl -pe 's/^((.*)\.doc)$/git mv -f $1 $2.doc/i' | source /dev/stdin

Bu, tüm .docdosyaların uzantılarının küçük harfli olmasını sağlar .

Ve bu tesadüfen halledilebilir xargs, ama asıl mesele bu.

find . -type f -iname '*.doc' | ack -v '\.doc$' | perl -pe 's/^((.*)\.doc)$/$1 $2.doc/i' | xargs -L1 git mv

Yani, ilkini çalıştırdığımda, hemen çıkacak, hiçbir şey olmuyor.


Karmaşık komutunuz, önce bir geçici dosyaya yönlendirdiğinizde ve sonra onu kaynakladığınızda çalışıyor mu? Değilse, üretilen çıktıyla ilgili sorun nedir? Dosya adlarınızda boşluklar varsa veya belirli diziler düzgün şekilde atlanmadıysa, komutunuzun çıktısı çalışmayacaktır. Minimum 1 $ ve 2. $ dolardan fiyat teklifi eklemek istiyorum.
Kaleb Pederson

Bunu orijinal kabukta çalıştırmanın iyi bir nedeni var mı? - bu örnekler mevcut kabuğu değiştirmez, böylece bunu yaparak hiçbir şey kazanmazsınız. Hızlı çözüm, çıktıyı bir dosyaya yeniden yönlendirmek ve bu dosyayı kaynaklamaktır
nos

@kaleb çıktı iyi çalışıyor. bu özel durumda, sh to sh. dosya adları yer kaplamaz, ancak not ettiğiniz için teşekkürler. Orijinal kabukta @nos git ortam değişkenleri. ve yine, bunlar sadece örneklerdir. soru yaşam içindir.
kch

source / dev / stdin, atanmış değişkenlere bağlı kalmaya ihtiyaç duyduğumda benim için çalışmadı. freenode bash üzerindeki geirha beni mywiki.wooledge.org/BashFAQ/024 adresine yönlendirdi ve benim için çalışan bir işlem ikame kaynağı <(komut)
denememi önerdi

Yanıtlar:


88
$ ls | sed ... | source /dev/stdin

GÜNCELLEME: Bu bash 4.0 eserleri yanı sıra tcsh ve tire (değiştirmek eğer sourceiçin .). Görünüşe göre bu bash 3.2'de hatalıydı. Gönderen bash 4,0 sürüm notları :

". '' E neden olan bir hata düzeltildi. aygıtlar veya adlandırılmış yöneltmeler gibi normal olmayan dosyalardan komutları okuyup yürütememek.


Oh, ve kabukları listelediğiniz için, zsh olarak da çalışıyor.
kch

2
Msys / mingw'de (/ dev klasörünün (hatta aygıtların) olmadığı yerlerde) deneyene kadar bunun dahice olduğunu düşündüm! Eval, $ () ve ters işaretlerin birçok kombinasyonunu denedim ``. , bu yüzden sonunda çıktıyı geçici bir dosyaya yeniden yönlendirdim, geçici dosyayı kaynaklandırdım ve kaldırdım. Temelde "sed ...> /tmp/$$.tmp &&. /tmp/$$.tmp && rm / tmp / $$. tmp ". Geçici dosyaları olmayan bir msys / mingw çözümü olan herkes ???
chriv

10
Sadece bir not: Bu, ihracat beyanlarını beklendiği gibi ele almıyor. Borulu dizede bir dışa aktarma ifadesi varsa, exportet değişkeni daha sonra terminal ortamınızda mevcut olmaz, oysa eval ile dışa aktarma da mükemmel çalışır.
Phil

Son boru seçeneği ayarlanmadan bash'de, bu, aynen | bashyapacağı gibi bir alt kabuk oluşturur
diğer adam

1
MacOS X'in genellikle bash 3.2'ye sahip olduğu (belki Yosemite'de 4.0?) Ve benim kullanım durumumda lastpipe hile ihtiyacım olduğu için (bir dosyadaki tüm değişkenleri, her satırı sed ile önceden işleyerek dışa aktararak 'dışa aktar') ile gitmek eval "$(sed ...)"yaklaşımı - ama 3.2 hata Uyarı için teşekkürler!
Alex Dupuy

135

evalKomut bu çok amaç için vardır.

eval "$( ls | sed... )"

Bash kılavuzundan daha fazlası :

değerlendirme

          eval [arguments]

Bağımsız değişkenler, daha sonra okunup çalıştırılan tek bir komutta birlikte birleştirilir ve çıkış durumu eval'un çıkış durumu olarak döndürülür. Bağımsız değişken yoksa veya yalnızca boş bağımsız değişkenler varsa, dönüş durumu sıfırdır.


8
Buradaki tek sorun, komutlarınızı ayırmak için; 'ler eklemeniz gerekebilmesidir. Bu yöntemi AIX, Sun, HP ve Linux üzerinde çalışmak için kendim kullanıyorum.
Tanktalus

Tanktalus, bu yorum için teşekkürler, senaryomun çalışmasını sağladı. Benim makinemde eval yeni satırlarda ayrı komutlar vermez ve kaynak kullanımı noktalı virgüllerde bile çalışmaz. Noktalı virgülle değerlendirme çözümdür. Keşke sana birkaç puan verebilseydim.
Milan Babuškov

2
@ MilanBabuškov: Onu sizin için sıraladım ;-)
Phil

3
Bu mükemmel. Bununla birlikte, kullanım durumum için, $ () değerimin etrafına tırnak işareti koymak zorunda kaldım, şu şekilde: eval "$( ssh remote-host 'cat ~/.bash_profile' )"Gerçekten bash 3.2 kullanıyorum.
Zachary Murray

3
Bu, kabul edilen cevabın olmadığı yerde benim için işe yarar.
Dan Tenenbaum

37

Vay canına, bunun eski bir soru olduğunu biliyorum, ama son zamanlarda kendimi aynı problemle buldum (buraya böyle geldim).

Her neyse - source /dev/stdincevabı beğenmedim ama sanırım daha iyisini buldum. Aslında aldatıcı derecede basit:

echo ls -la | xargs xargs

Güzel, değil mi? Aslında, bu yine de istediğinizi yapmaz, çünkü birden fazla satırınız varsa, her komutu ayrı ayrı çalıştırmak yerine onları tek bir komutta birleştirir. Yani bulduğum çözüm şudur:

ls | ... | xargs -L 1 xargs

-L 1seçenek 1 satır komut yürütme başına (en fazla) kullanması demektir. Not: Satırın sonunda boşluk varsa, sonraki satırla birleştirilecektir! Bu nedenle, her satırın boşluksuz olarak bittiğinden emin olun.

Sonunda yapabilirsin

ls | ... | xargs -L 1 xargs -t

hangi komutların çalıştırıldığını görmek için (-t ayrıntılıdır).

Umarım birisi bunu okur!


31

Bir komutun çıktısını, daha sonra kaynaklanabilecek geçici bir dosyayla değiştiren işlem ikamesi kullanmayı deneyin :

source <(echo id)

7
Bu ne tür bir büyü?
paulotorrens

1
Bu benim de ilk düşüncemdi. Değerlendirme çözümünü daha çok sevmeme rağmen. @PauloTorrens <(xyz) basitçe xyz'i çalıştırır ve <(xyz) 'i xyz çıktısını yazacak bir dosyanın adıyla değiştirir. Örneğin şunu yaparak bunun nasıl çalıştığını anlamak gerçekten çok kolay: echo <(echo id)çıktıyı vererek /dev/fd/12(12 bir örnektir), cat <(echo id)çıktıyı vererek idve sonra source <(echo id)aynı çıktıyı sadece yazarak vermekid
netigger

2
@PauloTorrens, buna işlem ikamesi denir . Resmi açıklama için bağlantılı belgelere bakın, ancak kısa yanıt "<()" nin bu gibi durumlar göz önünde bulundurularak tasarlanmış özel bir sözdizimi olduğudur.
Mark Stosberg

1
@MarkStosberg, bunun özel bir sözdizimi (...)mi yoksa sadece bir alt kabuğun yönlendirildiğini biliyor musunuz?
paulotorrens

2
@PauloTorrens, sadece işlem ikamesi için özel bir sözdizimidir.
Mark Stosberg

6

Bunun soruya "doğru cevap" olduğuna inanıyorum:

ls | sed ... | while read line; do $line; done

Yani, bir whiledöngü halinde boru olabilir ; readKomut komut kaynaklarından seçtiği bir satır alır stdindeğişkene ve ona atar $line. $linedaha sonra döngü içinde yürütülen komut olur; ve girişinde başka satır kalmayana kadar devam eder.

Bu yine de bazı kontrol yapılarında (başka bir döngü gibi) çalışmayacaktır, ancak bu durumda faturaya uymaktadır.


5
`ls | sed ...`

Bir çeşit hissediyorum gibi ls | sed ... | source -güzel olurdu, ama ne yazık ki sourceanlamıyor -demek stdin.


mark4o'nun cevabını gördükten sonra, bunca zamandır yüzümüzde olduğu gibi gelmiyor mu?
kch

Heh, evet. O şeyin var olduğunu asla hatırlamıyorum.
kaos

1

Çözümünüzün ters işaretlerle komut ikamesi olduğunu düşünüyorum: http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html

3.4.5 bölümüne bakın


3
Bash kullanıyorsanız $( )sözdizimi tercih edilebilir. 'Parkur geri
tepeleri

6
$ (command) ve $ ((1 + 1)) tüm posix kabuklarında çalışır. Sanırım pek çoğu onları sözdizimi hataları olarak işaretleyerek erteliyor, ancak bunun nedeni vim'in çok azının kullandığı orijinal Bourne kabuğunu vurgulaması. Vim'in doğru şekilde vurgulamasını sağlamak için bunu .vimrc dosyanıza koyun: let g: is_posix = 1
pixelbeat

1

Mark4o'nun çözümünü bash 3.2'de (macos) kullanmak için, bu örnekte olduğu gibi ardışık düzenler yerine bir here dizisi kullanılabilir:

. /dev/stdin <<< "$(grep '^alias' ~/.profile)"

veya ters tikleri kullanın:. / dev / stdin <<< "grep '^ alias' ~ / .profile`
William

0

sourceO zaman neden kullanmıyorsun ?

$ ls | sed ... > out.sh ; source out.sh

Geçici dosyaların kötü olduğundan bahsetti.
kaos
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.