Bash'deki bir değişkene bir yorumlu değer nasıl atanır?


374

Bu çok satır dize (tırnak dahil) var:

abc'asdf"
$(dont-execute-this)
foo"bar"''

Bash'ta bir yorumlu metin kullanarak bir değişkene nasıl atayabilirim?

Yeni satırları korumam gerekiyor.

Dizedeki karakterlerden kaçmak istemiyorum, bu sinir bozucu olurdu ...


@JohnM - Ben sadece CDR komut 'EOF'ile kaçan satır satırları ile tek tırnaklı bir yorumlu atama denedim ` in the content: if the second line has , ben geri alıyorum: " .sh: line X: cd: komut bulunamadı "; ama çift tırnak koyarsam "EOF"; bash değişkenleri ${A}dize olarak korunmaz (genişler); ama sonra, hat sonları vardır korunmuş - Ben bir komutu çalıştırarak bir sorun yok ve cdikinci satırda ( ve hem 'EOF' ve "EOF" iyi de oynamak gibi evalsaklanan komutlar kümesi çalıştırmak için, dize değişkeni ). Şerefe!
— sdaau

1
... ve önceki yorumuma eklemek için: çift yönlü "EOF"değişkendeki bash yorumları "#" , çağrılırsa eval $VAR, komut dosyasının geri kalanının yorumlanmasına neden olur, çünkü burada $ VAR tek bir satır olarak görülecektir ; bash #yorumlarını çok satırlı komut dosyasında kullanabilmek için çift eval call: tırnaklı "eval" $ VAR değişkeninde de değişkendir .
— sdaau

@sdaau: evalBu yöntemlerle ilgili sorunlar yaşadım , ancak evalyapılandırma dosyasında tanımlanan bazı değişkenler olan bazı paketlerin bir parçası olduğu için izlemedim . Hata mesajı vardı: /usr/lib/network/network: eval: line 153: syntax error: unexpected end of file. Yeni bir çözüme geçtim.
— Golar Ramblar

Yanıtlar:


515

catBununla eşleşmeyen teklifleri işe yaramaz şekilde kullanmaktan kaçınabilirsiniz :

$ read -r -d '' VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF

Değişkeni yankıladığınızda alıntılamazsanız, yeni satırlar kaybolur. Alıntı yapmak onları korur:

$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''

Kaynak koddaki okunabilirlik için girintiyi kullanmak istiyorsanız, daha az tondan sonra bir tire kullanın. Girinti sadece sekmeler kullanılarak yapılmalıdır (boşluk bırakılmamalıdır).

$ read -r -d '' VAR <<-'EOF'
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''
    EOF
$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''

Bunun yerine, sonuçtaki değişkenin içeriğindeki sekmeleri korumak istiyorsanız, sekmeyi kaldırmanız gerekir IFS. Buradaki doc ( EOF) için terminal işareti girintili olmamalıdır.

$ IFS='' read -r -d '' VAR <<'EOF'
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''
EOF
$ echo "$VAR"
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''

Tab basarak komut satırında sokulabilir Ctrl- V Tab. Bir düzenleyici kullanıyorsanız, hangisine bağlı olarak, bu da işe yarayabilir veya sekmeleri otomatik olarak boşluklara dönüştüren özelliği kapatmanız gerekebilir.


117
Eğer betiğinizde set -o errexit(aka set -e) varsa ve bunu kullanırsanız, betiğinizi sonlandırır çünkü readEOF'a ulaştığında sıfır olmayan bir dönüş kodu döndürür.
— Mark Byers

14
@MarkByers: Bu asla kullanmamamın set -eve her zaman kullanılmamasını önermemin nedenlerinden biri . Bunun yerine uygun hata işlemeyi kullanmak daha iyidir. trapsenin arkadaşın. Diğer arkadaşlar: elseve ||diğerleri arasında.
— sonraki duyuruya kadar duraklatıldı.

7
catBöyle bir durumda kaçınmaya gerçekten değer mi? Bir değişkenle bir yorumlu metin atamak catiyi bilinen bir deyimdir. Her nasılsa readküçük faydalar imho şeyler şeyler gizler.
— Gregory Pakosz

6
@ulidtko Bunun nedeni dile boş dize arasında boşluk olmaması ; bashçökmeler -rd''basitçe için -rdönce readbu kadar, onun argümanları gördüğü VARiçin argüman olarak kabul edilir -d.
— chepner

6
Bu biçimde, readsıfırdan farklı bir çıkış kodu ile döner. Bu, hata denetimi etkinleştirilmiş bir komut dosyasında (ör. set -e) Bu yöntemi ideal olandan daha az yapar .
— İsviçre

245

catDeğişkeninize çıktısını şu şekilde atamak için $ () kullanın :

VAR=$(cat <<'END_HEREDOC'
abc'asdf"
$(dont-execute-this)
foo"bar"''
END_HEREDOC
)

# this will echo variable with new lines intact
echo "$VAR"
# this will echo variable without new lines (changed to space character)
echo $VAR

END_HEREDOC başlangıcını tek tırnakla sınırlandırdığınızdan emin olun.

Sonlandırma sınırlayıcı sınırlayıcısının END_HEREDOCsatırda yalnız olması gerektiğini unutmayın (bu nedenle sonlandırma parantezi sonraki satırdadır ).

@ephemientCevabınız için teşekkürler .


1
Aslında, bu bazı durumlarda alıntılar yapmanıza izin verir. Bunu Perl'de kolayca yapmayı başardım ...
— Neil

32
+1. Bu, en azından gözlerim için en okunabilir çözüm. Değişkenin adını, okuma komutuna gömmek yerine sayfanın en solunda bırakır.
— Clayton Stanley

12
PSA: satırsonlarını korumak için değişkenin tırnak içine alınması gerektiğini unutmayın . echo "$VAR"yerine echo $VAR.
— sevko

7
Bu hoş ashve OpenWRT nerede readdesteklemiyor -d.
— David Ehrmann

3
Sebebi çekemediğim nedenlerden dolayı, bir yorumda eşleştirilmemiş bir geri tepme varsa, "beklenmedik bir EOF" hatasıyla başarısız olur .
— Radon Rosborough

79

Bu Dennis yönteminin bir çeşididir, senaryolarda daha zarif görünüyor.

fonksiyon tanımı:

define(){ IFS='\n' read -r -d '' ${1} || true; }

kullanımı:

define VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF

echo "$VAR"

zevk almak

ps desteklemeyen kabuklar için bir 'okuma döngüsü' sürümü yaptı read -d. çalışmalı set -euve eşleştirilmemiş backticks ile çalışmalı , ancak çok iyi test edilmemelidir:

define(){ o=; while IFS="\n" read -r a; do o="$o$a"'
'; done; eval "$1=\$o"; }

1
Bu sadece yüzeysel olarak işe yarıyor gibi görünüyor. Define işlevi 1 durumunu döndürür ve neyin düzeltilmesi gerektiğinden emin değilim.
— fny

1
Bu da kabul edilen cevaptan üstündür, çünkü bash'a ek olarak POSIX sh'yi desteklemek için değiştirilebilir ( readfonksiyondaki bir döngü, -d ''yeni satırları korumak için gerekli bashizmden kaçınmak için ).
— ELLIOTTCABLE

Alt kabuktaki kedi seçeneğinden farklı olarak, bu yorumlu metinte eşleştirilmemiş backticks ile çalışır . Teşekkür ederim!
— Radon Rosborough

Bu çözüm set -eset ile çalışır , ancak seçilen cevap çalışmaz. http://unix.stackexchange.com/a/265151/20650
— Nedeniyle

2
@fny ps dönüş durumu uzun zamandır düzeltildi
— ttt

36
VAR=<<END
abc
END

çalışmıyor çünkü stdin'i umursamayan bir şeye, yani atamaya yönlendiriyorsunuz

export A=`cat <<END
sdfsdf
sdfsdf
sdfsfds
END
` ; echo $A

çalışıyor, ancak orada bunu kullanmanızı engelleyebilecek bir arka tic var. Ayrıca, backticks kullanmaktan kaçınmalısınız, komut değiştirme gösterimini kullanmak daha iyidir $(..).

export A=$(cat <<END
sdfsdf
sdfsdf
sdfsfds
END
) ; echo $A

Sorumu $ (yürütülebilir) içerecek şekilde güncelledim. Ayrıca, yeni satırları nasıl korursunuz?
— Neil

2
@ l0st3d: Çok yakın ... $(cat <<'END'Bunun yerine kullanın . @Neil: Son satırsonu değişkenin bir parçası olmayacak, gerisi korunacak.
— ephemient

1
Yeni satırlar korunmuş gibi görünmüyor. Yukarıdaki örneği çalıştırıyorum: "sdfsdf sdfsdf sdfsfds" ... ah! Ama yazma echo "$A"(yani A çift tırnak içine koyarak) ve satırsonu görüyorsun!
— Darren Cook

1
@Darren: aha! Newlines sorununu fark etmiştim ve çıktı değişkeninin etrafındaki tırnak işaretlerini kullanmak sorunu çözüyor. Teşekkür!
— javadba

1
İlginçtir, zira ilk örnek cilvesi, bir tutam böyle eğreti açıklama bloğu için kullanabilirsiniz: REM=<< 'REM' ... comment block goes here ... REM. Veya daha kompakt : << 'REM' .... "REM", "NOTLAR" veya "SCRATCHPAD" vb. Gibi bir şey olabilir.
— Beejor

34

Hala yeni satırları koruyan bir çözüm yok.

Bu doğru değil - muhtemelen sadece yankı davranışı tarafından yanlış yönlendiriliyorsunuz:

echo $VAR # strips newlines

echo "$VAR" # preserves newlines


5
Gerçekten bu, bir değişkenin alıntısının nasıl çalıştığıdır. Tırnaklar olmadan, bunları farklı parametreler olarak ekler, alan sınırlandırılır, tırnaklarla tüm değişken içerikleri tek bir argüman olarak ele alınır
— Czipperz

11

Neil'in cevabını dallamak , genellikle bir değişkene ihtiyacınız yoktur, bir işlevi bir değişkenle aynı şekilde kullanabilirsiniz ve okumak satır içi veya readtabanlı çözümlerden çok daha kolaydır .

$ complex_message() {
  cat <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
}

$ echo "This is a $(complex_message)"
This is a abc'asdf"
$(dont-execute-this)
foo"bar"''

9

Dizi bir değişkendir, bu durumda mapfile çalışır

mapfile y <<z
abc'asdf"
$(dont-execute-this)
foo"bar"''
z

Sonra böyle yazdırabilirsiniz

printf %s "${y[@]}"

3

bir değişkene yorumlu değer atama

VAR="$(cat <<'VAREOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
VAREOF
)"

bir komutun argümanı olarak kullanılır

echo "$(cat <<'SQLEOF'
xxx''xxx'xxx'xx  123123    123123
abc'asdf"
$(dont-execute-this)
foo"bar"''
SQLEOF
)"

İlk yöntemi denediğimde, hatlar arasında hat sonlandırıcı yok gibi görünüyor. Linux makinemde bir tür yapılandırma olmalı mı?
— Kemin Zhou

Bu muhtemelen değişkeninizi yankıladığınız zaman, onun içine tırnak echo "$VAR"
— Brad Parks

1

Kendimi içinde NULL ile bir dize okumak zorunda buldum, bu yüzden burada her şeyi okuyacak bir çözüm . Aslında NULL ile uğraşıyorsanız, onaltılık seviyede bununla uğraşmanız gerekecektir.

$ cat> read.dd.sh

read.dd() {
     buf= 
     while read; do
        buf+=$REPLY
     done < <( dd bs=1 2>/dev/null | xxd -p )

     printf -v REPLY '%b' $( sed 's/../ \\\x&/g' <<< $buf )
}

Kanıt:

$ . read.dd.sh
$ read.dd < read.dd.sh
$ echo -n "$REPLY" > read.dd.sh.copy
$ diff read.dd.sh read.dd.sh.copy || echo "File are different"
$ 

HEREDOC örneği (^ J, ^ M, ^ I ile):

$ read.dd <<'HEREDOC'
>       (TAB)
>       (SPACES)
(^J)^M(^M)
> DONE
>
> HEREDOC

$ declare -p REPLY
declare -- REPLY="  (TAB)
      (SPACES)
(^M)
DONE

"

$ declare -p REPLY | xxd
0000000: 6465 636c 6172 6520 2d2d 2052 4550 4c59  declare -- REPLY
0000010: 3d22 0928 5441 4229 0a20 2020 2020 2028  =".(TAB).      (
0000020: 5350 4143 4553 290a 285e 4a29 0d28 5e4d  SPACES).(^J).(^M
0000030: 290a 444f 4e45 0a0a 220a                 ).DONE

0

Dimo414'ün cevabı için teşekkürler , kolayca yanı metinde tırnak ve değişkenleri sahip olabileceği bu onun harika bir çözüm nasıl çalıştığını gösterir ve gösteriler:

örnek çıktı

$ ./test.sh

The text from the example function is:
  Welcome dev: Would you "like" to know how many 'files' there are in /tmp?

  There are "      38" files in /tmp, according to the "wc" command

test.sh

#!/bin/bash

function text1()
{
  COUNT=$(\ls /tmp | wc -l)
cat <<EOF

  $1 Would you "like" to know how many 'files' there are in /tmp?

  There are "$COUNT" files in /tmp, according to the "wc" command

EOF
}

function main()
{
  OUT=$(text1 "Welcome dev:")
  echo "The text from the example function is: $OUT"
}

main

Bunu nasıl ele aldığını görmek için metinde eşsiz bir alıntı görmek ilginç olurdu. Belki 'çıldırmayın, "$ COUNT" dosya var`, bu yüzden kesme işareti / tek alıntı ilginç şeyler yapabilir.
— dragon788

-10
$TEST="ok"
read MYTEXT <<EOT
this bash trick
should preserve
newlines $TEST
long live perl
EOT
echo -e $MYTEXT
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.