Bash'de yalnızca tanımlanmış değişkenler (kabuk ve / veya ortam değişkenleri) nasıl yazdırılır


57

Bash builtin komutu set, eğer argümanlar olmadan çağrılırsa, tüm kabuk ve çevre değişkenlerini ve aynı zamanda tanımlanmış tüm fonksiyonları yazdıracaktır. Bu, çıktıyı insanlar için kullanılamaz hale getirir ve zorlaştırır grep.

Bash yerleşik komutunun setişlevleri değil yalnızca değişkenleri yazdırmasını nasıl sağlayabilirim ?

İşlevsiz sadece kabuk değişkenlerini basan başka komutlar var mı?

Not: bash, kabuk değişkenleri ile çevre değişkenleri arasında ayrım yapar. bkz. çevre değişkenleri ve dışa aktarılan çevre değişkenleri arasındaki fark bash

Yanıtlar:


51

"İşlevsiz, yalnızca kabuk değişkenlerini basan başka komutlar var mı?"

Man bash, SHELL BUILTIN KOMUTLARI bölümünde (set bölümünde) şöyle yazıyor: "Posix modunda, sadece kabuk değişkenleri listeleniyor."

(set -o posix; set)

not: ()sentaks bir alt kabuk ortaya çıkar, eğer çatal istemezsen sadece daha ayrıntılı versiyonunu kullan

set -o posix; set; set +o posix

1
Bugüne kadarki en iyi çözüm
Ruslan,

1
_Kurtulmak kolay, genellikle ilgi çekici olmayan değişkenler vardır:(set -o posix ; set | grep -v ^_)
hyde

Bu beni çok uzun zamandır rahatsız ediyor! Çok satırlı değerlere sahipseniz _ ile başlayan satırları kaldırmak yeterli değil, yine de değerin içeriğini dokunuşta bırakacaktır. Ayarlanan satırları sırayla yazdırdığından, tüm _ satırları sonunda olacaktır, böylece ilk _ satırından sonra sonuçları kolayca kesebilirsiniz:set -o posix; set | sed -e '/^_/,$d'; set +o posix;
Scott

1
Sadece bir not: parantez içinde önemlidir (set -o posix; set). Parantezler olmadan mevcut Bash kabuğunun davranışı Posix standardına uyacak şekilde değiştirilecektir. (Dunno bunun ne anlama geldiğini ancak önemli göründüğünü söyler.) Parantez ile Bash değişmeden kalır.
John Red,

1
Yan etkileri : Kümeler POSIXLY_CORRECT=yve ekler posixiçin$SHELLOPTS
Tom Hale

31

İşte bazı geçici çözümler:

$ comm -3 <(declare | sort) <(declare -f | sort)

Yıkmak:

  1. declare Her tanımlanmış değişkeni (dışa aktarılan veya dışlanan) ve işlevini yazdırır.
  2. declare -f sadece işlevleri yazdırır.
  3. comm -3Her ikisi için ortak olan tüm satırları kaldıracak. Aslında bu, sadece değişkenleri bırakarak fonksiyonları kaldıracaktır.

Yalnızca dışa aktarılmayan değişkenleri yazdırmak için:

$ comm -3 <(comm -3 <(declare | sort) <(declare -f | sort)) <(env | sort)

Başka bir geçici çözüm:

$ declare -p

Bu sadece değişkenleri yazdıracak, fakat bazı çirkin niteliklere sahip olacaktır.

declare -- BASH="/bin/bash"
declare -ir BASHPID=""
declare -A BASH_ALIASES='()'
declare -a BASH_ARGC='()'
...

Öznitelikleri keserek kesebilirsin ... cut:

$ declare -p | cut -d " " -f 3

Bir dezavantajı, IFS'nin değerinin sergilenmek yerine yorumlanmasıdır.

karşılaştırmak:

$ comm -3 <(declare | sort) <(declare -f | sort)
...
IFS=$' \t\n'
...
$ declare -p | cut -d " " -f 3
...
IFS="
"
...

Bu, "bir satırdaki yalnızlık nedeniyle, bu çıktının ileri işleme için kullanılmasını oldukça zorlaştırır . Bunu önlemek için belki bir miktar IFS-fu yapılabilir.


Başka bir geçici çözüm, compgenşunları kullanarak :

$ compgen -v

Bash yerleşiminin compgentamamlama komut dosyalarında kullanılması amaçlanmıştır. Bu amaçla, compgen -vtanımlanmış tüm değişkenleri listeler. Dezavantajı: değerleri değil, sadece değişken isimlerini listeler.

Burada ayrıca değerleri listelemek için bir kesmek.

$ compgen -v | while read var; do printf "%s=%q\n" "$var" "${!var}"; done

Avantaj: Saf bir soluk çözeltisidir. Dezavantaj: yorumlanmasından dolayı bazı değerler berbat olur printf. Ayrıca borudan ve / veya döngüden alt kabuk bazı ekstra değişkenler ekler.


senin gelmez declare ...| cutbir değişken için hiçbir nitelikler varsa boru kırmak? --Bu durumda kullanıldığını tahmin ediyorum , ama hala tedirginim. sedyani, daha güvenli olabilirdeclare -p | sed 's/^.* \([^ ]\+\)$/\1/'
jmtd 12:11

compgen:) için +1
RSFalcon7

13

typesetYerleşik garip sadece (fonksiyonlarını göstermek için bir seçenek vardır -fsadece parametreleri göstermek için) ancak. Neyse ki, typeset(veya set) tüm işlevler gösterilmeden önce tüm işlevler, işlev ve parametre adları yeni satırlar veya eşit işaretler içeremez ve parametre değerlerinde yeni satırlar alıntılanır (gibi görünürler \n). Böylece, eşit bir işaret içermeyen ilk satırda durabilirsiniz:

set | awk -F '=' '! /^[0-9A-Z_a-z]+=/ {exit} {print $1}'

Bu yalnızca parametre adlarını yazdırır; Değerleri istiyorsanız, değiştirmek print $1için print $0.

Bunun yalnızca parametre değişkenlerini değil ("ortam değişkeni" "dışa aktarılmış parametrelerle" eş anlamlı olduğunu) tüm parametre adlarını (parametreler ve değişkenler burada eş anlamlı olarak kullanıldığını) yazdırdığını unutmayın.

Bunun, parametre adlarındaki bash sınırlamaları ile eşleşmeyen bir isimle ortam değişkeni olmadığını varsaydığını da unutmayın. Bu tür değişkenler bash içinde yaratılamaz, ancak bash başladığında çevreden miras kalmış olabilir:

env 'foo ()
{
  =oops' bash

Harika çözüm! '=' Olmayan ilk satırda durmayı bile düşünmedim. +1
Steven D

Eşdeğer, sed ile: set | sed '/=/!Q'
Toby Speight

7

Birinin setyalnızca değişkenleri nasıl yazdıracağından emin değilim . Ancak çıktısına bakarak, setsadece değişkenleri kapmak gibi görünen aşağıdakileri ortaya koydum:

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" 

Temel olarak, harf, sayı veya noktalama işaretleriyle başlayan ve ardından "=" ile başlayan satırları arıyorum. Gördüğüm çıktıdan itibaren, bu değişkenlerin tümünü kapar; ancak bunun çok taşınabilir olduğundan şüpheliyim.

Başlığınızın önerdiği gibi, bu listeden dışa aktarılan değişkenleri çıkarmak ve böylece dışa aktarılmayan değişkenlerin bir listesini almak istiyorsanız, bunun gibi bir şey yapabilirsiniz.

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars && env | sort | comm -23 ./setvars - 

Bunu biraz parçalamak için, işte yaptığı:

  1. set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars : Bu umarım tüm değişkenleri (daha önce tartışıldığı gibi) alır, sıralar ve sonucu bir dosyaya yapıştırır.
  2. && env | sort: Önceki komut tamamlandıktan sonra, envçıktısını arayacak ve sıralayacağız.
  3. | comm -23 ./setvars -: Son olarak, sıralı çıktısını boruya envaktarıyoruz commve -23ilk argümana özgü satırları, bu durumda setten çıktımıza özgü satırları yazdırma seçeneğini kullanıyoruz .

Tamamladığınızda, komut ile oluşturduğu geçici dosyayı temizlemek isteyebilirsiniz. rm ./setvars


Komutunuzla ilgili sorun taşınabilirlik değildir (elbette bash’a özgüdür, ama grep tarafında bir sorun yoktur). Sorun, fonksiyon tanımlarında bazı satırları kapamanızdır. Bash girintiler fonksiyon kodunun en ama hepsini değil, özellikle (İçeride belgeleri metin değil f () {|cat <<EOF|foo=bar|EOF|}nerede |bir satır sonu gösterir).
Gilles 'SO- kötülük olmayı'


2

Printenv komutunu deneyin:

$printenv

6
printenv ve env yalnızca dışa aktarılan (ortam) değişkenleri yazdırır ve dışa aktarılmayan (kabuk) değişkenleri yazdırmaz.
Lri

@ Lri Teşekkürler! Dışa aktarılan değişkenleri nasıl yazdıracağımı merak ettim.
Mark Stewart

1

Bash, bu sadece değişken isimleri basacaktır:

compgen -v

Veya, değerler de gerekliyse, şunları kullanın:

declare -p

çabanız için teşekkürler. Lütfen cevabımdaki unix.stackexchange.com/a/5691/1170 adresindeki ihtimalimin yine de bir artığı olduğunu söylemiştim.
lesmana

0

rc betiklerin dışarıda kalmasının da değişmesini sağlamak için temiz bir kabuğa karşı farklılaşma

## get mostly local vars
diff_env(){
    diff <(bash -cl 'set -o posix && set') \
        <(set -o posix && set && set +o posix) | \
        grep -E "^>|^\+" | \
        grep -Ev "^(>|\+|\+\+) ?(BASH|COLUMNS|LINES|HIST|PPID|SHLVL|PS(1|2)|SHELL|FUNC)" | \
        sed -r 's/^> ?|^\+ ?//'
}

ile sürüm commçok sarsılmış olurdu


0

Kabul edilen cevap harika. POSIX modunu ayarlamayı içermeyen bir alternatif sunuyorum:

İşte fonksiyon durumunu bir dosyaya kaydetmek için kullandığım teknik, böylece daha sonra devam edebiliyorum. Birincisi bir durum dökümü üretir, ikincisi ise değişken isimlerinin sadece bir listesini çıkarır.

set 2>/dev/null | while read a; do [[ $a == *=* ]] || break; echo $a; done 

set 2>/dev/null | while read a; do [[ $a == *=* ]] || break; echo ${a/=*}; done 

Her ikisi de, ilk işlev listelendiğinde ortaya çıkan '=' char'siz bir tane bulana kadar satırları dökerek çalışır. İkincisi, ödevi keser.

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.