Sh olarak bir dizede nasıl yeni satır alabilirim?


339

Bu

STR="Hello\nWorld"
echo $STR

çıktı olarak üretilir

Hello\nWorld

onun yerine

Hello
World

Bir dizede yeni satır almak için ne yapmalıyım?

Not: Bu soru yankı ile ilgili değildir . Farkındayım echo -e, ancak yeni satırlar olarak yorumlamak için benzer bir seçeneğe sahip olmayan diğer komutlara bir dize (bir satırsonu içeren) argümanı geçirmeyi sağlayan bir çözüm arıyorum \n.

Yanıtlar:


353

Çözüm, $'string'örneğin:

$ STR=$'Hello\nWorld'
$ echo "$STR" # quotes are required here!
Hello
World

İşte Bash kılavuz sayfasından bir alıntı:

   Words of the form $'string' are treated specially.  The word expands to
   string, with backslash-escaped characters replaced as specified by  the
   ANSI  C  standard.  Backslash escape sequences, if present, are decoded
   as follows:
          \a     alert (bell)
          \b     backspace
          \e
          \E     an escape character
          \f     form feed
          \n     new line
          \r     carriage return
          \t     horizontal tab
          \v     vertical tab
          \\     backslash
          \'     single quote
          \"     double quote
          \nnn   the eight-bit character whose value is  the  octal  value
                 nnn (one to three digits)
          \xHH   the  eight-bit  character  whose value is the hexadecimal
                 value HH (one or two hex digits)
          \cx    a control-x character

   The expanded result is single-quoted, as if the  dollar  sign  had  not
   been present.

   A double-quoted string preceded by a dollar sign ($"string") will cause
   the string to be translated according to the current  locale.   If  the
   current  locale  is  C  or  POSIX,  the dollar sign is ignored.  If the
   string is translated and replaced, the replacement is double-quoted.

74
Bu geçerli bir bash ama POSIX sh değil.
jmanning2k

7
+ 1-sadece bir not: export varDynamic = "$ varAnother1 $ varAnother2" $ '\ n'
Yordan Georgiev

3
Bu gerçekten OP'nin istediği gibi gerçek dizelerle çalışır, ancak değişkenler değiştirilir değiştirilmez başarısız olur: STR=$"Hello\nWorld"basitçe yazdırır Hello\nWorld.
ssc

3
@ssc tek tırnak, çift değil
miken32

7
@ssc örneğinizde değişken yok. Ayrıca, bu yöntem tek tırnak gerektirir. Son olarak, enterpolasyonlu değişkenleri dahil etmek için çift tırnaklı ve özel tek tırnaklı dizeleri birlikte birleştirmeniz gerekir. örneğin H="Hello"; W="World"; STR="${H}"$'\n'"${W}"; echo "${STR}""Merhaba" ve "Dünya"

166

Yankı o kadar doksanlı ve tehlikelerle doludur ki kullanımı 4GB'tan az olmayan çekirdek dökülmelerine neden olmalıdır. Ciddi olarak, eko'nun sorunları, Unix Standardizasyon sürecinin nihayetinde printftüm problemleri ortadan kaldırarak programı icat etmesinin nedeniydi .

Bir dizede yeni satır almak için:

FOO="hello
world"
BAR=$(printf "hello\nworld\n") # Alternative; note: final newline is deleted
printf '<%s>\n' "$FOO"
printf '<%s>\n' "$BAR"

Orada! SYSV ve BSD yankı çılgınlığı yok, her şey C kaçış dizileri için düzgün bir şekilde basılır ve tamamen taşınabilir destek alır. Herkes lütfen printfşimdi kullanın ve asla geriye bakmayın.


3
Bu cevap için teşekkürler, bence gerçekten iyi tavsiyeler veriyor. Bununla birlikte, asıl sorumun, yeni satırları yazdırmak için yankı nasıl alınacağı değil, yeni satırın kabuk değişkenine nasıl getirileceği ile ilgili olduğunu unutmayın. Sen de o kullanarak printf nasıl yapılacağını gösterir, ancak ben gelen çözüm olduğunu düşünüyorum amphetamachine kullanarak $'string'bile temizleyicidir.
Juan A. Navarro

11
Sadece 'temiz' eksik tanımı için. $'foo'Sözdizimi şikayet 2013 Birçok kabukları itibariyle geçerli POSIX sözdizimi değil.
Jens

5
BAR=$(printf "hello\nworld\n")benim için sondaki izi yazdırmıyor \ n
Jonny

3
@Jonny Yapmamalı; komut değiştirme için kabuk belirtimi, çıktının sonunda bir veya daha fazla satırın silindiğini belirtir. Bunun benim örneğim için beklenmedik olduğunu fark ettim ve printf'e bir satırsonu ekleyecek şekilde düzenledim.
Jens

5
@ismael No, $()POSIX tarafından , değiştirme işleminin sonunda bir veya daha fazla <newline> karakterin dizilerini kaldırmak olarak belirtilir .
Jens

61

Diğer cevaplara dayanarak yaptığım şey

NEWLINE=$'\n'
my_var="__between eggs and bacon__"
echo "spam${NEWLINE}eggs${my_var}bacon${NEWLINE}knight"

# which outputs:
spam
eggs__between eggs and bacon__bacon
knight

30

Sorun kabukla ilgili değil. Sorun aslında echokomutun kendisi ve değişken enterpolasyon etrafında çift tırnak olmamasıdır. Kullanmayı deneyebilirsiniz, echo -eancak bu tüm platformlarda desteklenmez ve printfartık taşınabilirlik için nedenlerinden biri önerilmektedir.

Ayrıca, yeni satırı doğrudan kabuk komut dosyanıza ekleyebilir (bir komut dosyası yazdığınız şeyse), bu yüzden ...

#!/bin/sh
echo "Hello
World"
#EOF

Veya eşdeğer olarak

#!/bin/sh
string="Hello
World"
echo "$string"  # note double quotes!

24

-eBayrağı şık ve düz buluyorum

bash$ STR="Hello\nWorld"

bash$ echo -e $STR
Hello
World

Dize başka bir komutun çıktısıysa, sadece tırnak işaretleri kullanıyorum

indexes_diff=$(git diff index.yaml)
echo "$indexes_diff"

2
Bu, diğer cevaplarda zaten belirtilmiştir. Ayrıca, zaten orada olmasına rağmen, bu sorunun ilgili olmadığı gerçeğini vurgulamak için soruyu yeni düzenledim echo.
Juan A. Navarro

Bu sorunun cevabı değil
Rohit Gupta

Bu aradığım soruyu tamamen cevaplıyor! Teşekkürler!
Kieveli

1
Burada benim için iyi çalıştı. Ben bu yankıyı dayalı bir dosya oluşturmak için kullandım ve çıktı doğru yeni satırlar oluşturdu.
Mateus Leon

echo -etaşınabilirlik sorunları ile ünlüdür. Bu, şu anda POSIX öncesi bir Vahşi Batı durumundan daha az, ancak yine de tercih etmek için bir neden yok echo -e. Ayrıca bkz. Stackoverflow.com/questions/11530203/…
tripleee

21
  1. Tek basit alternatif aslında değişkene yeni bir satır yazmaktır:

    $ STR='new
    line'
    $ printf '%s' "$STR"
    new
    line

    Evet, bu Enter, kodda gereken yere yazma anlamına gelir .

  2. Bir new linekarakterin birkaç eşdeğeri vardır .

    \n           ### A common way to represent a new line character.
    \012         ### Octal value of a new line character.
    \x0A         ### Hexadecimal value of a new line character.

    Ancak tüm bunlar bir araç tarafından "yorum" gerektirir ( POSIX printf ):

    echo -e "new\nline"           ### on POSIX echo, `-e` is not required.
    printf 'new\nline'            ### Understood by POSIX printf.
    printf 'new\012line'          ### Valid in POSIX printf.
    printf 'new\x0Aline'       
    printf '%b' 'new\0012line'    ### Valid in POSIX printf.

    Bu nedenle, yeni satır içeren bir dize oluşturmak için araç gereklidir:

    $ STR="$(printf 'new\nline')"
    $ printf '%s' "$STR"
    new
    line
  3. Bazı kabuklarda, dizi $' özel bir kabuk genişlemesidir. Ksh93, bash ve zsh'de çalıştığı biliniyor:

    $ STR=$'new\nline'
  4. Tabii ki, daha karmaşık çözümler de mümkündür:

    $ echo '6e65770a6c696e650a' | xxd -p -r
    new
    line

    Veya

    $ echo "new line" | sed 's/ \+/\n/g'
    new
    line

6

Tek tırnak işaretlerinden hemen önce bir '... \ n ...' işareti var, ancak çift tırnak işareti çalışmıyor.

$ echo $'Hello\nWorld'
Hello
World
$ echo $"Hello\nWorld"
Hello\nWorld

4

Ben bash uzmanı değilim, ama bu benim için çalıştı:

STR1="Hello"
STR2="World"
NEWSTR=$(cat << EOF
$STR1

$STR2
EOF
)
echo "$NEWSTR"

Bunu metinleri biçimlendirmek için daha kolay buldum.


2
İyi yaşlı bir yorumcu . Ve muhtemelen POSIX uyumlu!
pyb

Etrafında tırnak $NEWSTRiçinde echo "$NEWSTR"burada önemli olan
vasiliy

0

Sistemimde (Ubuntu 17.10) örneğiniz hem komut satırından (içine sh) yazıldığında hem de komut shdosyası olarak yürütüldüğünde istediğiniz gibi çalışır :

[bash sh
$ STR="Hello\nWorld"
$ echo $STR
Hello
World
$ exit
[bash echo "STR=\"Hello\nWorld\"
> echo \$STR" > test-str.sh
[bash cat test-str.sh 
STR="Hello\nWorld"
echo $STR
[bash sh test-str.sh 
Hello
World

Sanırım bu sorunuza cevap veriyor: sadece işe yarıyor. (Böyle şey şu an için yeni satır karakterinin tam ikame itibariyle detaylar dışında şekle denemedim \nolur sh).

Ancak, ben çalıştırıldığında bu aynı komut dosyası farklı davranabilir olacağını fark ilebash ve çıktısını olur Hello\nWorldyerine:

[bash bash test-str.sh
Hello\nWorld

bashAşağıdaki gibi istenilen çıktıyı almayı başardım :

[bash STR="Hello
> World"
[bash echo "$STR"

Etraftaki çift tırnaklara dikkat edin $STR. Bu, kaydedildiğinde ve bashkomut dosyası olarak çalıştırıldığında aynı şekilde davranır .

Aşağıdakiler ayrıca istenen çıktıyı verir:

[bash echo "Hello
> World"

0

Sadece satırsonuna ihtiyaç duyan ve girintiyi kıran çok satırlı kodu hor gören seçici olanlar şunları yapabilirdi:

IFS="$(printf '\nx')"
IFS="${IFS%x}"

Bash (ve muhtemelen diğer kabuklar) komut değiştirildikten sonra tüm satır sonlarını kaldırır, bu nedenle printfdizeyi yeni satır olmayan bir karakterle sonlandırmanız ve daha sonra silmeniz gerekir. Bu aynı zamanda kolayca bir oneliner olabilir.

IFS="$(printf '\nx')" IFS="${IFS%x}"

Bunun bir yerine iki eylem olduğunu biliyorum, ama girintim ve taşınabilirlik OKB artık barış içinde :) Başlangıçta bunu sadece satırsonu ayrılmış çıktıyı bölmek için geliştirdim \rve sonlandırma karakteri olarak kullanılan bir modifikasyon kullanarak sona erdim. Bu, satırsonu ile biten dos çıkışı için bile yeni satır ayırmayı çalıştırır \r\n.

IFS="$(printf '\n\r')"

0

Buradaki seçeneklerden hiç memnun kalmadım. Bu benim için işe yaradı.

str=$(printf "%s" "first line")
str=$(printf "$str\n%s" "another line")
str=$(printf "$str\n%s" "and another line")

Bu yazmanın çok sıkıcı bir yoludur str=$(printf '%s\n' "first line" "another line" "and another line")(kabuk, komut satırındaki son satır sonlarını uygun şekilde keser (ya da kesmez)). Burada birkaç cevap zaten printfçeşitli şekillerde teşvik , bu yüzden bunun ayrı bir cevap olarak herhangi bir değer kattığından emin değilim.
Üçlü

Kısa dizeler içindir, ancak işleri düzenli tutmak istiyorsanız ve her satır aslında 60 karakter uzunluğundaysa, bunu yapmanın düzenli bir yoludur. Sonunda gittiğim çözüm olduğu göz önüne alındığında, sizin için değilse, şüphesiz geri döndüğümde gelecekte kendim için bir şeyler ekliyor.
Adam K Dean

1
Uzun dizeler için bile printf '%s\n' "first line" \ (satırsonu, girinti) 'second line'vb. Tercih ederim printf -v str.
Üçlü
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.