Bir değişkeni değerini kaybetmeden nasıl dışa aktarabilirim?


10

Diyelim ki bir değişken ihraç ettim:

foo=bar
export foo

Şimdi, ihracatını kaldırmak istiyorum. Yani, eğer yapsam sh -c 'echo "$foo"'anlamamalıyım bar. foohiç bir sh -cortamda görünmemelidir . sh -csadece bir örnektir, bir değişkenin varlığını göstermenin kolay bir yoludur. Komut herhangi bir şey olabilir - davranışı sadece değişkenin ortamındaki varlığından etkilenen bir şey olabilir.

Yapabilirim:

  1. unset değişken ve kaybetmek
  2. envHer komut için şunu kullanarak kaldırın :env -u foo sh -c 'echo "$foo"'
    • geçerli kabuğu bir süre kullanmaya devam etmek istiyorsanız kullanışsız.

İdeal olarak, değişkenin değerini korumak istiyorum, ancak boş bir değişken olarak bile değil, bir alt süreçte hiç görünmesini istemem.

Sanırım yapabilirim:

otherfoo="$foo"; unset foo; foo="$otherfoo"; unset otherfoo

otherfooZaten varsa, bu durma riski taşır .

Tek yol bu mu? Standart yollar var mı?


1
Sen kullanarak geçici dosyaya değerini yankı olabilir mktempeğer o source değişkeni atamak için geçici dosya taşınabilir yeterlidir ve değersiz bırakılarak tanımsız ve. En azından geçici bir dosya, bir kabuk değişkeninin aksine az ya da çok keyfi bir adla oluşturulabilir.
Thomas Dickey

@Sukminder sh -cKomut sadece bir örnektir. İçerisinde, bir değişkeni yerine atayamayacağınız herhangi bir komutu alın.
muru

Yanıtlar:


6

Standart bir yol yok.

Bir işlevi kullanarak geçici bir değişken kullanmaktan kaçınabilirsiniz. Aşağıdaki işlev ayarlanmamış değişkenleri ayarlanmamış ve boş değişkenleri boş tutmaya özen gösterir. Ancak, salt okunur veya yazılan değişkenler gibi bazı kabuklarda bulunan özellikleri desteklemez.

unexport () {
  while [ "$#" -ne 0 ]; do
    eval "set -- \"\${$1}\" \"\${$1+set}\" \"\$@\""
    if [ -n "$2" ]; then
      unset "$3"
      eval "$3=\$1"
    fi
    shift; shift; shift
  done
}
unexport foo bar

Ksh, bash ve zsh'de bir değişkeni dışa aktarabilirsiniz typeset +x foo. Bu, tipler gibi özel özellikleri korur, bu nedenle kullanılması tercih edilir. Bir tek şey kabuklar düşünüyorum typesetyerleşiğini var typeset +x.

case $(LC_ALL=C type typeset 2>&1) in
  typeset\ *\ builtin) unexport () { typeset +x -- "$@"; };;
  *) unexport () {  };; # code above
esac

1
Bilgisi olmayanlar ${var+foo}, bu kadar değerlendirir fooeğer var, ayarlanmış olsa bile boş ise ve hiçbir şey başka türlü.
muru

Söyleyin, eskisini destekleyen mermiler için typeset +xvs ile export -nilgili yorumlarınız var mı? Mı export -nnadir, yoksa bazı özelliklerini korumaz?
muru

@muru Bir bash betiği yazıyorsanız, export -nveya typeset +xkayıtsız kullanabilirsiniz . Ksh veya zsh'de sadece vardır typeset +x.
Gilles 'SO- kötü olmaktan kaçın'

7

DÜZENLEME: For bashsadece Açıklamalarda belirttiği gibidir:

-nSeçeneği exportuzaklaşmaların exporther verilen isimden özelliği. (Bkz help export.)

Yani için bash, istediğiniz komut şöyledir:export -n foo


1
Kabuğa özgü ( POSIX'e bakın ), OP bir kabuk belirtmedi, ancak sorunu çözmenin standart bir yolunu istedi .
Thomas Dickey

1
@ThomasDickey, bunun farkında değildi. Teşekkürler, güncellendi.
Joker

3

Benzer bir POSIX işlevi yazdım, ancak bu rastgele kod yürütülmesini riske atmıyor:

unexport()
    while case ${1##[0-9]*} in                   ### rule out leading numerics
          (*[!_[:alnum:]]*|"")                   ### filter out bad|empty names
          set "" ${1+"bad name: '$1'"}           ### prep bad name error
          return ${2+${1:?"$2"}}                 ### fail w/ above err or return 
          esac
    do    eval  set '"$'"{$1+$1}"'" "$'"$1"'" "$'@\" ###  $1 = (  $1+ ? $1 : "" )
          eval  "${1:+unset $1;$1=\$2;} shift 3"     ### $$1 = ( $1:+ ? $2 : -- )
    done

Ayrıca, sağlamayı düşündüğünüz kadar çok argümanı da ele alacaktır. Bağımsız değişken, başka bir şekilde ayarlanmamış geçerli bir adsa, sessizce yoksayılır. Bağımsız değişken kötü bir adsa, stderr'e yazar ve uygun şekilde durur, ancak komut satırında geçersiz olandan önceki geçerli ad yine de işlenir.

Başka bir yol düşündüm. Çok daha hoşuma gitti.

unexport()
        while   unset OPTARG; OPTIND=1           ### always work w/ $1
                case  ${1##[0-9]*}    in         ### same old same old
                (*[!_[:alnum:]]*|"")             ### goodname && $# > 0 || break
                    ${1+"getopts"} : "$1"        ### $# ? getopts : ":"
                    return                       ### getopts errored or ":" didnt
                esac
        do      eval   getopts :s: '"$1" -"${'"$1+s}-\$$1\""
                eval   unset  "$1;  ${OPTARG+$1=\${OPTARG}#-}"
                shift
        done

Her ikisi de aynı teknikleri kullanıyor. Temel olarak, bir kabuk değişkeni ayarlanmamışsa, ona bir başvuru bir +parametre genişletmesiyle genişletilmez. Ancak, değerinden bağımsız olarak ayarlanırsa , değişkenin değerine değil : gibi bir parametre genişletmesi ${parameter+word}genişler word. Ve böylece kabuk değişkenleri kendini test eder ve kendini yerine geçer.

Ayrıca kendi kendine başarısız olabilirler . Üst işlevde kötü bir ad bulunursa içeri $1girer $2ve $1null bırakırım çünkü yaptığım bir sonraki şey ya returntüm argümanlar işlenmişse ve döngü sonundaysa ya da arg geçersizse, kabuk genişletmek $2içine $1:?hangi bir metne kabuk öldürmek ve yazarken interaktif birine bir kesme dönecektir wordstderr'e.

İkincisinde getoptsödevler yapılır. Ve kötü bir ad atamaz - bunun yerine yazma stderr'e standart bir hata mesajı yazacaktır. Dahası , argüman ilk etapta bir set değişkeninin adı $OPTARG ise arg değerini kaydeder . Yani getoptsgereken her şeyi yaptıktan sonra evalbir setin OPTARGuygun atamaya genişlemesi.


2
Bu günlerden birinde, başımı cevaplarınızdan birinin etrafına sarmaya çalıştıktan sonra bir yerlerde psikiyatri koğuşunda olacağım. : D Diğer cevap rasgele kod yürütülmesinden nasıl etkileniyor? Bir örnek verebilir misiniz?
muru

3
@muru - bağımsız değişken geçersiz bir ad olmadığı sürece değil. ama sorun bu değil - sorun girişin onaylanmamış olmasıdır. evet, rasgele kod yürütmesi için garip bir adla bir argüman iletmeniz gerekiyor - ancak bu, tarihin her CVE'sinin temelini oluşturuyor. exportgarip bir isim denerseniz , bilgisayarınızı öldürmez.
mikeserv

1
@muru - oh, ve argümanlar keyfi olabilir: var=something; varname=var; export "$varname"tamamen geçerlidir. aynı şey geçerlidir unsetve bununla ve diğeriyle birlikte, ancak bu "$varname"değişkenin içeriği çıldırdığında pişman olabilir. ve tüm bu bashişlev ihracatı zaten böyle oldu.
mikeserv

1
@mikeserv Ben bu gizli kodu kendini açıklayan (veya en azından satırları yorumladı) kodu ile değiştirirseniz (en azından benden) çok daha fazla upvotes alırsınız düşünüyorum
PSkocik

1
@PSkocik - bitti.
mikeserv
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.