Bash'teki bir komuttan önce bir ortam değişkeni ayarlamak bir borudaki ikinci komut için çalışmıyor


351

Belirli bir kabukta, normalde bir değişken veya değişkenler ayarlayıp bir komut çalıştırırdım. Son zamanlarda bir komuta değişken tanım önermesi kavramını öğrendim:

FOO=bar somecommand someargs

Bu işe yarıyor ... biraz. Eğer bir LC_ * değişkeni değiştiriyoruz zaman çalışmaz (komutu etkileyecek gibi görünüyor, ama değil onun argümanları örneğin, '[az]' karakter aralıkları) ya da thusly başka bir komuta çıkış boru zaman:

FOO=bar somecommand someargs | somecommand2  # somecommand2 is unaware of FOO

Ben de çalışır, ancak istenmeyen çoğaltma ekler ve değişkene (örneğin, '[az]') yorumlanır bağımsız değişkenler ile yardımcı olmaz "FOO = bar" ile somecommand2 başa.

Peki, bunu tek bir satırda yapmanın iyi bir yolu nedir?

Ben şu sırayla bir şey düşünüyorum:

FOO=bar (somecommand someargs | somecommand2)  # Doesn't actually work

Bir sürü iyi cevap aldım! Amaç, bunu tercihen "dışa aktarma" kullanmadan tek astar olarak tutmaktır. Bash çağrısı kullanan yöntem genel olarak en iyisiydi, ancak içindeki "dışa aktarma" olan parantez sürümü biraz daha kompakttı. Bir boru yerine yeniden yönlendirme kullanma yöntemi de ilginçtir.


1
(T=$(date) echo $T)çalışacak
vp_arth

Çapraz platform (pencereler dahil) komut dosyaları veya npm tabanlı projeler (js veya başka) bağlamında, çapraz env modülüne bakmak isteyebilirsiniz .
Frank Nocke

5
Cevaplardan birinin neden bu tür çalışmaların neden açıklandığını , yani çağrıdan önce değişkeni dışa aktarmaya eşdeğer olmadığını umuyordum .
Brecht Machiels

4
Neden burada açıklanmaktadır: stackoverflow.com/questions/13998075/…
Brecht Machiels

Yanıtlar:


317
FOO=bar bash -c 'somecommand someargs | somecommand2'

2
( "İhracat" gerek kalmadan tek satırlık) Bu tatmin benim kriterleri ... Ben bunu yapmak için hiçbir yolu yoktur almak olmadan "bash -c" (parantez örneğin yaratıcı kullanımını) çağırarak?
MartyMacGyver

1
@MartyMacGyver: Aklıma gelen hiçbir şey yok. Kıvırcık parantezlerle de çalışmaz.
sonraki duyuruya kadar duraklatıldı.

7
Eğer somecommandsudo olarak çalıştırmanız gerekiyorsa, -Edeğişkenlerden geçmek için sudo bayrağını geçirmeniz gerektiğini unutmayın . Çünkü değişkenler güvenlik açıklarına neden olabilir. stackoverflow.com/a/8633575/1695680
ThorSummoner

11
Komutunuzda zaten iki düzey tırnak varsa, bu yöntem alıntı cehenneminden dolayı son derece tatmin edici olmayacaktır. Bu durumda alt kabukta ihracat çok daha iyidir.
Pushpendre

Tek: OSX'te FOO_X=foox bash -c 'echo $FOO_X'beklendiği gibi çalışır, ancak belirli var adlarıyla başarısız olur: DYLD_X=foox bash -c 'echo $DYLD_X'echos blank. her ikisi de evalyerine kullanarak çalışırbash -c
mwag

209

Değişkeni yalnızca alt kabuğun içinde dışa aktarmaya ne dersiniz ?:

(export FOO=bar && somecommand someargs | somecommand2)

Keith'in bir anlamı var, koşulsuz olarak komutları yürütmek için şunu yapın:

(export FOO=bar; somecommand someargs | somecommand2)

15
Ben kullanmak ;yerine &&; export FOO=barbaşarısız olmanın bir yolu yok .
Keith Thompson

1
@MartyMacGyver: &&sol komutu yürütür, ardından yalnızca sol komut başarılı olursa sağ komutu yürütür. ;her iki komutu da koşulsuz olarak yürütür. Windows toplu ( cmd.exebir) eşdeğer ;olduğunu &.
Keith Thompson

2
Zsh olarak ben bu sürüm için ihracat ihtiyacı görünmüyor: (FOO=XXX ; echo FOO=$FOO) ; echo FOO=$FOOverimler FOO=XXX\nFOO=\n.
rampion

3
@PopePoopinpants: neden bu durumda source(aka .) kullanmıyorsunuz ? Ayrıca, bugünlerde backticks kullanılmamalıdır ve bu kullanımın $(command)daha güvenli olmasının nedenlerinden biridir .
0xC0000022L

3
Çok basit, ama çok zarif. Ve cevabınızı kabul edilen cevaptan daha iyi seviyorum, çünkü mevcut olanıma eşit bir alt kabuk başlatacak (ki olmayabilir bashama başka bir şey olabilir, örneğin dash) ve tırnak kullanmam gerekirse herhangi bir sorunla karşılaşmıyorum args ( someargs) komutunun içinde .
Mecki

45

Ayrıca şunları kullanabilirsiniz eval:

FOO=bar eval 'somecommand someargs | somecommand2'

Bu cevap evalherkesi memnun etmediği için, bir şeyi açıklığa kavuşturacağım: yazılı olarak kullanıldığında , tek tırnaklarla , tamamen güvenlidir. Harici bir işlemi başlatmayacağı (kabul edilen cevap gibi) veya komutları ekstra bir alt kabukta (diğer cevap gibi) yürütmeyeceği için iyidir.

Birkaç düzenli görüş aldığımızda, evalherkesi memnun edecek bir alternatif vermek muhtemelen iyidir ve bu hızlı eval"numara" nın tüm faydalarına (ve belki de daha fazlasına!) Sahiptir. Sadece bir işlev kullanın! Tüm komutlarınızla bir işlev tanımlayın:

mypipe() {
    somecommand someargs | somecommand2
}

ve bunu aşağıdaki gibi ortam değişkenlerinizle yürütün:

FOO=bar mypipe

7
@Alfe: Kabul edilen cevabı da düşürdünüz mü? çünkü aynı “problemleri” sergiler eval.
gniourf_gniourf

10
@Alfe: maalesef eleştirinize katılmıyorum. Bu komut tamamen güvenlidir. Gerçekten okuma kere birisine gibi ses evalkötülüğü olduğu hakkında neyin en kötülüğü anlamadan eval. Ve belki de sonuçta bu cevabı gerçekten anlamıyorsunuz (ve gerçekten yanlış bir şey yok). Aynı seviyede: bunun lskötü olduğunu söyler misiniz çünkü for file in $(ls)kötüdür? (ve evet, kabul edilen cevabı küçümsemediniz ve yorum da bırakmadınız). SO bazen çok garip ve saçma bir yer.
gniourf_gniourf

7
Dediğimde: @Alfe Gerçekten okuma bir kez adam gibisin evalhakkında kötü ne anlamadan kötülük olduğunu eval, senin cümlenin bahsediyorum: Bu cevap uyarıları ve gerekli açıklamaları bahsediyor hepsi yoksun eval. evalkötü ya da tehlikeli değildir; en fazla bash -c.
gniourf_gniourf

1
Oy bir yana, @Alfe verilen yorum bir şekilde kabul edilen cevabın bir şekilde daha güvenli olduğunu ima ediyor. Daha yararlı olabilecek şey, kullanımıyla ilgili güvensiz olduğuna inandığınız şeyi açıklamanız için olurdu eval. Değişken genişlemeden koruyan bağımsız değişkenlerin tek tırnak içinde yer alması şartıyla cevapta bir sorun görmüyorum.
Brett Ryan

Endişelerimi yeni bir yoruma yoğunlaştırmak için yorumlarımı kaldırdım: evalgenel olarak bir güvenlik meselesidir ( bash -cdaha az ama daha az açıktır), bu nedenle tehlikelerin kullanımını öneren bir cevapta belirtilmesi gerekir. Dikkatsiz kullanıcılar cevabı ( FOO=bar eval …) alabilir ve durumlarına uygulayabilir, böylece problem yaratır. Ancak, cevaplayıcı için herhangi bir şeyi geliştirmekten ziyade onun ve / veya diğer cevapların önemsiz olup olmadığını anlamak daha önemliydi. Daha önce yazdığım gibi, adalet ana endişe olmamalı; verilen herhangi bir cevaptan daha kötü olmak da dikkate alınmaz.
Alfe

12

kullanım env .

Örneğin env FOO=BAR command,. commandYürütme bittiğinde ortam değişkenlerinin geri yükleneceğini / değişmeyeceğini unutmayın .

Başvurmak istediğiniz takdirde sadece yani yaklaşık kabuk değiştirme olay hakkında dikkatli olun $FOO, aynı komut satırında açıkça, kendi kabuk tercüman ikame gerçekleştirmek kalmaması ondan kaçmak gerekebilir önce onu çalıştırır env.

$ export FOO=BAR
$ env FOO=FUBAR bash -c 'echo $FOO'
FUBAR
$ echo $FOO
BAR

-5

Kabuk betiği kullanın:

#!/bin/bash
# myscript
FOO=bar
somecommand someargs | somecommand2

> ./myscript

13
Hala ihtiyacın var export; aksi takdirde $FOObir kabuk değişkeni olacaktır, bir ortam değişkeni değildir ve bu nedenle somecommandveya tarafından görülemez somecommand2.
Keith Thompson

Çalışır, ancak tek satırlık bir komuta sahip olma amacını yener (nispeten basit durumlar için çok satırlı ve / veya komut dosyalarından kaçınmak için daha yaratıcı yollar öğrenmeye çalışıyorum). Ve @ Keith'in söylediği şey, en azından ihracat betiğin kapsamına girecekti.
MartyMacGyver
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.