$ PATH’a temiz bir şekilde nasıl ekleyebilirim?


31

Potansiyel olarak aynı yolu birden çok kez eklemeden $ PATH öğesine sistem genelinde veya tek bir kullanıcı için bir şeyler eklemenin bir yolunu istiyorum.

Bunu yapmak istemenin bir nedeni .bashrc, giriş yapılmasını gerektirmeyen ilavelerin girilebilmesi ve ayrıca lightdmasla aramayan sistemler (örneğin) kullanan sistemler için daha yararlı olmasıdır .profile.

$ PATH içinden kopyaların nasıl temizleneceği ile ilgili soruların farkındayım , ancak kopyaları kaldırmak istemiyorum . Yalnızca mevcut değilse, yolları eklemenin bir yolunu istiyorum .



goldi, neden bilmiyorum ama ilk yorumunuzu boş bile olsa gördüm. Ama evet, isim önekleri de işe yarıyor, endişelenme! Diğer tarafa kapanmak da iyidir.
Ciro Santilli,

Tamam, mesajımı aldığın sürece. Bazen bunun tersine çevrilmesi biraz kaosa neden olur, ne olacağını göreceğiz.
goldilocks

Yanıtlar:


35

Eklemek istediğimiz yeni yolun:

new=/opt/bin

Daha sonra, herhangi bir POSIX kabuğu kullanarak new, yolda olup olmadığını görmek için test edebilir ve değilse ekleyebiliriz:

case ":${PATH:=$new}:" in
    *:"$new":*)  ;;
    *) PATH="$new:$PATH"  ;;
esac

İki nokta üst üste kullanıldığına dikkat edin. İki nokta olmadan, örneğin, new=/bineşleşmesi nedeniyle zaten yolda olduğunu düşünebiliriz /usr/bin. PATH'lerin normalde birçok elemanı olmasına rağmen, PATH'daki özel sıfır ve bir eleman durumu da ele alınır. YOL başlangıçta herhangi bir öğe (boş olan) sahip olan durum kullanımı ile işlenir ve ${PATH:=$new}bu atar PATHiçin $newboş olup olmadığını. Parametreler için varsayılan değerleri bu şekilde ayarlamak, tüm POSIX kabuklarının bir özelliğidir: POSIX belgelerinin 2.6.2 bölümüne bakın .)

Çağrılabilir bir fonksiyon

Kolaylık sağlamak için yukarıdaki kod bir fonksiyona yerleştirilebilir. Bu işlev komut satırında tanımlanabilir veya kalıcı olarak kullanılabilir olması için kabuğunuzun başlatma komut dosyasına ekleyin (bash kullanıcıları için, bu olabilir ~/.bashrc):

pupdate() { case ":${PATH:=$1}:" in *:"$1":*) ;; *) PATH="$1:$PATH" ;; esac; }

Geçerli PATH'e bir dizin eklemek üzere bu yol güncelleme işlevini kullanmak için:

pupdate /new/path

@hammar Tamam. Bunun için bir dava ekledim.
John1024

1
2 farklı durumdan tasarruf edebilirsiniz - cf. unix.stackexchange.com/a/40973/1131 .
maxschlepzig

3
Eğer PATHboştur, buna (geçerli dizinde yani) boş bir giriş ekleyecektir PATH. Başka bir davaya ihtiyacın olduğunu düşünüyorum.
CB Bailey

2
@CharlesBailey Başka değil case. Sadece yap case "${PATH:=$new}". Benzer geri dönüşler için kendi cevabımı gör.
mikeserv

1
@ mc0e "Satır sesini" gizlemek için bir kabuk fonksiyonunun nasıl kullanılacağına bir örnek ekledim.
John1024

9

/etc/profile.dÖrneğin bir dosya oluşturun mypath.sh(veya ne istersen). Lightdm kullanıyorsanız, bunun geçerli olduğundan veya başka bir şekilde kullandığınızdan /etc/bashrcveya bir dosyadan kaynaklandığından emin olun . Buna, aşağıdaki işlevleri ekleyin:

checkPath () {
        case ":$PATH:" in
                *":$1:"*) return 1
                        ;;
        esac
        return 0;
}

# Prepend to $PATH
prependToPath () {
        for a; do
                checkPath $a
                if [ $? -eq 0 ]; then
                        PATH=$a:$PATH
                fi
        done
        export PATH
}

# Append to $PATH
appendToPath () {
        for a; do
                checkPath $a
                if [ $? -eq 0 ]; then
                        PATH=$PATH:$a
                fi
        done
        export PATH
}

$ PATH'un başlangıcındaki (aşağıda belirtilenler) baştaki şeyler aşağıdakilere göre önceliklidir ve tersine, sonunda (eklenmiş olan) daha önce gelenlerin yerine geçecektir. Bu, $ PATH değeriniz varsa /usr/local/bin:/usr/binve gotchaher iki dizinde de çalıştırılabilir bir dosya varsa, biri /usr/local/binvarsayılan olarak kullanılacaktır.

Şimdi - bu aynı dosyada, başka bir kabuk yapılandırma dosyasında veya komut satırından - kullanabilirsiniz:

appendToPath /some/path /another/path
prependToPath /some/path /yet/another/path

Bu bir a ise .bashrc, yeni bir kabuk başlattığınızda değerin bir defadan fazla görünmesini önleyecektir. Önceden hazırlanmış bir şey eklemek istiyorsanız (yani $ PATH içinde bir yolu taşıyın) ya da tam tersi bir sınırlama vardır, bunu kendiniz yapmanız gerekir.


bölme $PATHile IFS=:daha nihayetinde daha esnektir case.
mikeserv

@mikeserv Hiç şüphesiz. Bu caseIMO için bir çeşit hack kullanımı . awkBurada da iyi kullanılabileceğini hayal ediyorum .
goldilocks

İyi bir noktaya değindin. Ve sanırım, gawkdoğrudan atayabilirim $PATH.
mikeserv

5

Bunu bu şekilde yapabilirsiniz:

echo $PATH | grep /my/bin >/dev/null || PATH=$PATH:/my/bin

Not: PATH'yi diğer değişkenlerden derlerseniz, boş olmadıklarını kontrol edin, çünkü birçok kabuk "" gibi "olarak yorumlanır. .


+1 Man sayfasına -qgöre POSIX tarafından grep için gerekli, ancak bunun hala sahip olmayan bazı (POSIX olmayan) grepler olduğu anlamına gelmiyor.
goldilocks

1
grep deseninin aşırı geniş olduğuna dikkat edin. Grep / my / bin> / dev / null yerine egrep -q "(^ |:) / my / bin (: | \ $)" komutunu kullanın. Bu değişiklikle çözümünüz doğrudur ve bence şu anda @ john1024 tarafından tercih edilen cevaptan daha okunaklı bir çözüm. Çift tırnak kullandığımı ve böylece değişken yerine ikame maddelerini kullandığımı unutmayın/my/bin
mc0e

5

Kodun önemli kısmı PATHbelirli bir yol içerip içermediğini kontrol etmektir :

printf '%s' ":${PATH}:" | grep -Fq ":${my_path}:"

Yani, her bir yolun her iki tarafta ayırıcı ( ) PATHile sınırlandırıldığından emin olun , ardından bir ayırıcı, yolunuz ve başka bir ayırıcıdan oluşan değişmez dizginin ( ) orada olup olmadığını kontrol edin ( ) . Yoksa, yolu güvenle ekleyebilirsiniz:PATH:-q-FPATHPATH

if ! printf '%s' ":${PATH-}:" | grep -Fq ":${my_path-}:"
then
    PATH="${PATH-}:${my_path-}"
fi

Bu POSIX uyumlu olmalı ve yeni satır karakteri içermeyen bir yolla çalışmalıdır. POSIX uyumlu iken newline içeren yollarla çalışmasını istiyorsanız daha karmaşık, ancak grephangisini destekliyorsanız, -zonu kullanabilirsiniz.


4

Bu küçük işlevi ~/.profileyıllardır yanımda çeşitli dosyalarda yanımda taşıyorum . Ben düşünüyorum ben iş için kullanılan bir laboratuarda sysadmin tarafından yazılmıştır ama emin değilim. Neyse, Goldilock'un yaklaşımına benzer, ancak biraz farklı:

pathmunge () {
        if ! echo $PATH | /bin/grep -Eq "(^|:)$1($|:)" ; then
           if [ "$2" = "after" ] ; then
              PATH=$PATH:$1
           else
              PATH=$1:$PATH
           fi
        fi
}

Yani, başına bir dizin eklemek için PATH:

pathmunge /new/path

ve sonuna:

pathmunge /new/path after

Bu benim için çalışıyor! Ama varsayılan olarak sonra koymak ve "önce" ile geçersiz kılmak için mantık değiştirdi. :)
Kevin Pauli

pathmunge, Linux centos dağılımının / etc / profile bir parçasıdır, önce ve sonra bir parametreye sahiptir. Son ubuntu
16'mda

MacOS 10.12'den sonra tamam görünüyormuş gibi görünüyor /bin/grep->grep
Ben Creasy

4

GÜNCELLEŞTİRME:

Kendi cevabınızın, eklemek veya hazırlamak için her birinin ayrı bir işlevi olduğunu fark ettim $PATH. Fikir hoşuma gitti. Bu yüzden küçük bir tartışma ele aldım. Ayrıca düzgün bir şekilde _ismini yazdım :

_path_assign() { oFS=$IFS ; IFS=: ; add=$* ; unset P A ; A=
    set -- ${PATH:=$1} ; for p in $add ; do {
        [ -z "${p%-[AP]}" ] && { unset P A
                eval ${p#-}= ; continue ; }
        for d ; do [ -z "${d%"$p"}" ] && break
        done ; } || set -- ${P+$p} $* ${A+$p}
        done ; export PATH="$*" ; IFS=$oFS
}

% PATH=/usr/bin:/usr/yes/bin
% _path_assign \
    /usr/bin \
    /usr/yes/bin \
    /usr/bin/nope \
    -P \
    /usr/nope/bin \
    /usr/bin \
    -A \
    /nope/usr/bin \
    /usr/nope/bin

% echo $PATH

ÇIKTI:

/usr/nope/bin:/usr/bin:/usr/yes/bin:/usr/bin/nope:/nope/usr/bin

Varsayılan olarak edecektir -Aiçin ppend $PATH, ancak bu davranışı değiştirebilir -Pbir ekleyerek repend -Pargümanlar listenizde hiçbir yerinde. Sen bunu geri dönebilirsiniz -Abir teslim tarafından ppending -Atekrar.

GÜVENLİ EVAL

Çoğu durumda, insanların herhangi bir kullanımından kaçınmalarını öneririm eval. Fakat bence bu, yararına kullanılmasının bir örneği olarak göze çarpıyor . Bu durumda, eval şimdiye kadar görebileceğiniz tek ifade P=veya A=. Argümanlarının değerleri, çağrılmadan önce kesinlikle test edilir. Bunun eval için var.

assign() { oFS=$IFS ; IFS=: ; add=$* 
    set -- ${PATH:=$1} ; for p in $add ; do { 
        for d ; do [ -z "${d%"$p"}" ] && break 
        done ; } || set -- $* $p ; done
    PATH="$*" ; IFS=$oFS
}

Bu, verdiğiniz kadar argümanı kabul eder ve her birini $PATHyalnızca bir defaya ve yalnızca önceden girilmemişse ekler $PATH. Yalnızca tamamen taşınabilir POSIX kabuk komut dosyasını kullanır, yalnızca kabuk yerleşik bileşenlerine güvenir ve çok hızlıdır.

% PATH=/usr/bin:/usr/yes/bin
% assign \
    /usr/bin \
    /usr/yes/bin \
    /usr/nope/bin \
    /usr/bin \
    /nope/usr/bin \
    /usr/nope/bin

% echo "$PATH"
> /usr/bin:/usr/yes/bin:/usr/nope/bin:/nope/usr/bin

@ TAFKA'goldilock 'güncellemeyi burada görün - bana ilham verdiniz.
mikeserv

+1 Merak etmediğinde (belki bu iyi bir ayrı soru cevap olabilir), _kabuk fonksiyonlarının ön ekinin onları "doğru şekilde adlandırılmış" hale getirme fikri nereden geliyor? Diğer dillerde, genellikle dahili bir küresel işlevi gösterir (yani, genel olması gereken, ancak harici olarak bir API'nin parçası olarak kullanılması amaçlanmamıştır). İsimlerim kesinlikle harika seçenekler değil, fakat sadece kullanmak bana göre _çarpışma sorunlarını çözmüyor - gerçek bir isim alanına dokunmak daha iyi olurdu, örneğin. mikeserv_path_assign().
goldilocks

@ TAFKA'goldilocks '- onunla daha da belirginleşmek daha iyi olurdu, ancak isim ne kadar uzun olursa o kadar az kullanışlı olur. Ancak, önceden eklenmiş herhangi bir uygun çalıştırılabilir ikili dosyaya sahipseniz, _paket yöneticilerini değiştirmeniz gerekir. Her durumda, bu, aslında, sadece bir "global, dahili, işlev" dir - ilan edildiği kabuktan çağrılan her kabuk için geneldir ve tercümanın hafızasına takılan sadece bir miktar yorumlanmış dil yazısıdır. . unix.stackexchange.com/questions/120528/…
mikeserv

unset aProfil sonunda (veya eşdeğeri) yapamaz mısın?
sourcejedi

0

Bakın! Endüstri gücü 12-line ... teknik olarak bash ve zsh-portatif kabuk fonksiyonu, sizin ~/.bashrcveya ~/.zshrcbaşlangıçtaki komut dosyasını sadık bir şekilde seviyor :

# void +path.append(str dirname, ...)
#
# Append each passed existing directory to the current user's ${PATH} in a
# safe manner silently ignoring:
#
# * Relative directories (i.e., *NOT* prefixed by the directory separator).
# * Duplicate directories (i.e., already listed in the current ${PATH}).
# * Nonextant directories.
+path.append() {
    # For each passed dirname...
    local dirname
    for   dirname; do
        # Strip the trailing directory separator if any from this dirname,
        # reducing this dirname to the canonical form expected by the
        # test for uniqueness performed below.
        dirname="${dirname%/}"

        # If this dirname is either relative, duplicate, or nonextant, then
        # silently ignore this dirname and continue to the next. Note that the
        # extancy test is the least performant test and hence deferred.
        [[ "${dirname:0:1}" == '/' &&
           ":${PATH}:" != *":${dirname}:"* &&
           -d "${dirname}" ]] || continue

        # Else, this is an existing absolute unique dirname. In this case,
        # append this dirname to the current ${PATH}.
        PATH="${PATH}:${dirname}"
    done

    # Strip an erroneously leading delimiter from the current ${PATH} if any,
    # a common edge case when the initial ${PATH} is the empty string.
    PATH="${PATH#:}"

    # Export the current ${PATH} to subprocesses. Although system-wide scripts
    # already export the ${PATH} by default on most systems, "Bother free is
    # the way to be."
    export PATH
}

Anlık zafer için kendinizi hazırlayın. Öyleyse, bunu yapmaktan ve en iyisini ummak yerine:

export PATH=$PATH:~/opt/bin:~/the/black/goat/of/the/woods/with/a/thousand/young

Bunu yapın ve gerçekten istese de istemeseniz de, en iyisini elde etme garantisi verin:

+path.append ~/opt/bin ~/the/black/goat/of/the/woods/with/a/thousand/young

Çok İyi, "En İyi" yi tanımlayın.

Akıntıya güvenli bir şekilde ekleme ve hazırlık yapma ${PATH}, genellikle olduğu gibi önemsiz bir mesele değildir. Uygun ve görünüşte mantıklı olsa da, formun tek gömlekleri aşağıdakilerle export PATH=$PATH:~/opt/binşeytani komplikasyonları davet eder:

  • Yanlışlıkla ilgili dizin isimleri (örneğin, export PATH=$PATH:opt/bin). İken bashve zshsessizce kabul ve çoğunlukla göreceli dirnames görmezden çoğu durumlarda, göreli dirnames biri tarafından öneki hveya tutanç verici hem neden (ve muhtemelen diğer kötü karakterler) Masaki Kobayashi'nin ala kendilerini sakatlamaya seminal 1962 başyapıt Harakiri :

    # Don't try this at home. You will feel great pain.
    $ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:harakiri && echo $PATH
    /usr/local/bin:/usr/bin:arakiri
    $ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:tanuki/yokai && echo $PATH
    binanuki/yokai   # Congratulations. Your system is now face-up in the gutter.
    
  • Yanlışlıkla yinelenen dizin isimleri. Yinelenen ${PATH}dizin adları büyük ölçüde zararsız olsa da, istenmeyen, hantal, hafif derecede verimsizdir, hata ayıklamayı engeller ve sürücü aşınmasını teşvik eder - bu cevabı benzer. NAND tarzı SSD'ler ( elbette ) okuma aşınmasına karşı bağışıklık kazanırken, HDD'ler değildir. Her denenen komutta gereksiz dosya sistemine erişim , aynı tempoda gereksiz okuma kafası aşınması anlamına gelir. Yinelenenler, iç içe geçmiş alt işlemlerde iç içe kabuklar çağırırken özellikle sıra dışıdır; bu noktada, gibi görünüşte masum olan tek gömlekleri export PATH=$PATH:~/wat, ${PATH}Cehennem Yedinci Çemberi'ne hızla patlarlar PATH=/usr/local/bin:/usr/bin:/bin:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat. Bunun üzerine ek dizinler eklerseniz, yalnızca Beelzebubba size yardımcı olabilir. (Bunun değerli çocuklarınıza olmasına izin vermeyin. )

  • Yanlışlıkla eksik dizin isimleri. Yine, eksik ${PATH}dizinler büyük ölçüde zararsız olsa da, aynı zamanda genellikle istenmeyen, hantal, hafif derecede verimsiz, hata ayıklama özelliğini engelleyen ve sürücü aşınmasını artıran unsurlardır.

Ergo, yukarıda tanımlanmış kabuk işlevi gibi dostane bir otomasyon. Kendimizi kendimizden kurtarmalıyız.

Ama ... Neden "+ path.append ()"? Neden Basitçe append_path ()?

Uyuşmazlık için (örneğin, ${PATH}başka bir yerde tanımlanmış olan geçerli veya sistem çapındaki kabuk işlevlerinde dış komutlarla ), kullanıcı tanımlı kabuk işlevleri, ideal olarak , standart komut temel adları tarafından desteklenen bashve zshancak başka şekilde yasaklanan benzersiz alt dizilerle ön eklenir veya eklenir +.

Hey. İşe yarıyor. Beni yargılama.

Ama ... Neden "+ path.append ()"? Neden "+ path.prepend ()" değil?

Çünkü ${PATH}akıntıya ekleme yapmak, akıntıya hazırlık yapmaktan daha güvenli olduğundan ${PATH}, her şey asla eşit olmadıkları için eşit olur. Kullanıcıya özgü komutlarla sistem genelinde komutları geçersiz kılmak, en iyi ihtimalle sağlıksız ve en kötü ihtimalle çılgınca olabilir. Örneğin, Linux altında, aşağı havzadaki uygulamalar genellikle standart olmayan türev ya da alternatiflerden ziyade GNU coreutils komut çeşitlerini beklerler .

Bununla birlikte, kesinlikle bunun için geçerli kullanım durumları vardır. Eşdeğer +path.prepend()işlevi tanımlamak önemsizdir. Sans prolix gizliliği, onun ve onun ortak akıl sağlığı için:

+path.prepend() {
    local dirname
    for dirname in "${@}"; do
        dirname="${dirname%/}"
        [[ "${dirname:0:1}" == '/' &&
           ":${PATH}:" != *":${dirname}:"* &&
           -d "${dirname}" ]] || continue
        PATH="${dirname}:${PATH}"
    done
    PATH="${PATH%:}"
    export PATH
}

Ama ... Neden Gilles değil?

Gilles ' kabul edilen cevabı başka yerde bir genel durumda etkileyici uygunudur 'agnostik İdempotent append kabuk' . Ortak bir durumda bashve zshile hiçbir istenmeyen sembolik Ancak performans cezası böylece üzer yapmak için gerekli Gentoo RICER içimde. İstenmeyen sembolik bağların varlığında bile, add_to_PATH()argüman başına bir alt kabuğun çatallanmasının , sembolik bağlantı kopyalarının potansiyel olarak eklenmesine değip değmeyeceği tartışmalıdır.

Hatta sembolik bağlantı kopukluklarının bile ortadan kaldırılmasını talep eden sıkı kullanım durumları için, bu özel zshdeğişken, verimli olmayan çatallardan ziyade verimli yerleşikler aracılığıyla bunu yapar:

+path.append() {
    local dirname
    for   dirname in "${@}"; do
        dirname="${dirname%/}"
        [[ "${dirname:0:1}" == '/' &&
           ":${PATH}:" != *":${dirname:A}:"* &&
           -d "${dirname}" ]] || continue
        PATH="${PATH}:${dirname}"
    done
    PATH="${PATH#:}"
    export PATH
}

Orijinalin *":${dirname:A}:"*yerine not alın *":${dirname}:"*. dahil pek çok kabuğun altında ne yazık ki bulunmayan :Abir harika . Alıntı yapmak için :zshbashman zshexpn

A : Bir dosya adını adeğiştirici gibi mutlak bir yola dönüştürün ve ardından realpath(3)sembolik bağları çözmek için sonucu kütüphane işlevinden geçirin. Not: Bir realpath(3)kütüphane işlevine sahip olmayan sistemlerde , sembolik bağlantılar çözülmez, bu sistemler üzerinde ave Aeşdeğerdir.

Daha fazla soru yok.

Rica ederim. Güvenli bombanın keyfini çıkarın. Şimdi bunu hak ettin.


0

İşte fonksiyonel programlama tarzı versiyonum.

  • Herhangi bir iki nokta sınırlamalı *PATHdeğişken için çalışır, yalnızca değil PATH.
  • Küresel duruma erişmiyor
  • Sadece belirtilen değişken girdilerle / üzerinde çalışır
  • Tek bir çıktı üretir
  • Yan efektleri olmayan
  • Memoize edilebilir (prensipte)

Ayrıca dikkat çekici:

  • İng ile ilgili Agnostik export; Arayana kalanlar (örneklere bakınız)
  • Saf bash; çatal yok
path_add () {
  # $ 1: Sağlanacak öğe tam olarak bir kez verilen yol dizesinde
  # $ 2: Mevcut yol dizesi değeri ("PATH" değil, "PATH" değil)
  # $ 3 (isteğe bağlı, herhangi bir şey): Verilirse, $ 1 ekleyin; aksi takdirde, hazırla
  #
  # Örnekler:
  # $ export PATH = $ (path_add '/ opt / bin' "$ PATH")
  # $ CDPATH = $ (path_add '/ Müzik' "$ CDPATH" at_end)

  local -r already_present = "(^ |:) $ {1} ($ | :)"
  eğer [["$ 2" = ~ $ zaten_present]]; sonra
    yankı "2 dolar"
  elif [[$ # == 3]]; sonra
    yankı "$ {2}: $ {1}"
  Başka
    yankı "$ {1}: $ {2}"
  fi
}

0

Bu komut dosyası sonunda eklemenizi sağlar $PATH:

PATH=path2; add_to_PATH after path1 path2:path3
echo $PATH
path2:path1:path3

Veya başında ekleyin $PATH:

PATH=path2; add_to_PATH before path1 path2:path3
echo $PATH
path1:path3:path2

# Add directories to $PATH iff they're not already there
# Append directories to $PATH by default
# Based on https://unix.stackexchange.com/a/4973/143394
# and https://unix.stackexchange.com/a/217629/143394
add_to_PATH () {
  local prepend  # Prepend to path if set
  local prefix   # Temporary prepended path
  local IFS      # Avoid restoring for added laziness

  case $1 in
    after)  shift;; # Default is to append
    before) prepend=true; shift;;
  esac

  for arg; do
    IFS=: # Split argument by path separator
    for dir in $arg; do
      # Canonicalise symbolic links
      dir=$({ cd -- "$dir" && { pwd -P || pwd; } } 2>/dev/null)
      if [ -z "$dir" ]; then continue; fi  # Skip non-existent directory
      case ":$PATH:" in
        *":$dir:"*) :;; # skip - already present
        *) if [ "$prepend" ]; then
           # ${prefix:+$prefix:} will expand to "" if $prefix is empty to avoid
           # starting with a ":".  Expansion is "$prefix:" if non-empty.
            prefix=${prefix+$prefix:}$dir
          else
            PATH=$PATH:$dir  # Append by default
          fi;;
      esac
    done
  done
  [ "$prepend" ] && [ "$prefix" != "" ] && PATH=$prefix:$PATH
}
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.