Fazladan boşluklu çok satırlı dize (korunmuş girinti)


410

Aşağıdaki özelliklere sahip bir dosyaya önceden tanımlanmış bazı metinler yazmak istiyorum:

text="this is line one\n
this is line two\n
this is line three"

echo -e $text > filename

Böyle bir şey bekliyorum:

this is line one
this is line two
this is line three

Ama şunu anladım:

this is line one
 this is line two
 this is line three

Her birinden sonra boşluk olmadığından eminim \n, ama fazladan alan nasıl çıkıyor?


2
Emin değilim ama .. nasıl sadece text="this is line one\nthis is line two\nthis is line three"bir satır yazdıysanız ..? (herhangi bir giriş olmadan)
Yohanes Khosiawan

4
\nHer satırdaki çizgiyi kaldırın, yeni satıra geçmek için yeni satıra
bastınız

Zaten verilen \nyeni hat sonraki satırı koymak neden .bu? Basitçetext="this is line one\nthis is line two\nthis is line three"
Jayesh Bhoi

1
\nHer satırın sonundan çıkarılması, çıktının tek bir satırda birlikte çalışmasına neden olur.
Jonathan Hartley

18
Aha: "$text"Yankı çizgisinin etrafına çift tırnak koymak çok önemli. Bunlar olmadan, yeni satırların hiçbiri (hem gerçek hem de '\ n') çalışmaz. Onlarla, hepsi yapar.
Jonathan Hartley

Yanıtlar:


663

Yorumlu metin bu amaç için daha uygun. Ex veya cat gibi bir komut yorumlayıcı programına birden fazla komut göndermek için kullanılır

cat << EndOfMessage
This is line 1.
This is line 2.
Line 3.
EndOfMessage

Sonraki dize <<nerede duracağını gösterir.

Bu satırları bir dosyaya göndermek için şunu kullanın:

cat > $FILE <<- EOM
Line 1.
Line 2.
EOM

Bu satırları bir değişkene de saklayabilirsiniz:

read -r -d '' VAR << EOM
This is line 1.
This is line 2.
Line 3.
EOM

Bu, satırları adlı değişkene kaydeder VAR.

Yazdırırken, değişkenin çevresindeki tırnak işaretlerini hatırlayın, aksi takdirde yeni satır karakterlerini görmezsiniz.

echo "$VAR"

Daha da iyisi, kodunuzda daha fazla öne çıkmak için girintiyi kullanabilirsiniz. Bu kez sadece eklemek -SONRA <<görünmesini sekmeleri durdurmak için.

read -r -d '' VAR <<- EOM
    This is line 1.
    This is line 2.
    Line 3.
EOM

Ancak, kodunuzda girinti için boşlukları değil sekmeleri kullanmalısınız.


38
Neden 2. ve 5. kod bloğunun ilk satırında << yerine << var? - özel bir şey yapar mı?
lohfu

35
@ sup3rman '-' Baştaki sekmeleri yok sayar. Bkz. Stackoverflow.com/questions/2500436/…
kervin

8
0 durumu ile nasıl okuma çıkışı yapabilirim? Satır sonu bulamıyor gibi görünüyor (çünkü -d '') ve senaryodayken yardımcı olmayan 1 ile çıkıyor.
Misha Slyusarev

7
@MishaSlyusarev -d '\ 0' kullanın ve son satırınızın sonuna \ 0 ekleyin
Lars Schneider

11
Bu -dseçeneği kullanmak read -r -d '' VARIABLE <<- EOMbenim için işe yaramadı.
dron22

186

Dizeyi bir değişkene almaya çalışıyorsanız, başka bir kolay yol şudur:

USAGE=$(cat <<-END
    This is line one.
    This is line two.
    This is line three.
END
)

Dizenizi sekmelerle girintili yaparsanız (yani, '\ t'), girinti çıkarılır. Boşluklarla girintilerseniz, girinti bırakılacaktır.

NOT: Son kapanış parantezinin başka bir satırda olması önemlidir. ENDMetin kendi başına bir satırda görünmelidir.


1
Bu önemli mi? Macimde )aynı satırda çalışır. Ne arasına gider çünkü düşünüyorum $(ve )kendi evrende yürütmek vermeyecek ve gerçek komut zaten ')' görmezsiniz. Başkaları için de işe yarayıp yaramadığını merak ediyorum.
deej

Farklı mermilerin işleri farklı şekilde yorumlaması mümkündür. Gelen bash belgelerinde Bir şey öyle ya da söylemek görünmüyor, ancak tüm örnekler kendi satırında da var.
Andrew Miner

Eğlenceli bir şey, ben de USAGE değişkeni için değer ayarlamaya çalışırken cevap buldum. Yani cevabınız tam olarak eşleşiyor. :)
Bunyk

1
@deej POSIX spesifikasyonundan : Buradaki belge… sadece sınırlayıcı ve bir <newline> içeren bir çizgi olana kadar devam eder
Fornost

1
@Fornost Söylediklerimle çelişmiyor
deej

84

echokendisine iletilen argümanlar arasına boşluk ekler. $textdeğişken genişleme ve kelime bölme işlemlerine tabidir, bu nedenle echokomutunuz şuna eşdeğerdir:

echo -e "this" "is" "line" "one\n" "this" "is" "line" "two\n"  ...

"This" den önce bir boşluk ekleneceğini görebilirsiniz. Yeni satır karakterlerini kaldırabilir ve yeni $textsatırları korumak için alıntı yapabilirsiniz :

text="this is line one
this is line two
this is line three"

echo "$text" > filename

Veya printfaşağıdakilerden daha sağlam ve taşınabilir olan kullanabilirsiniz echo:

printf "%s\n" "this is line one" "this is line two" "this is line three" > filename

Gelen bashayracı genişlemesini destekleyen, hatta yapabileceği:

printf "%s\n" "this is line "{one,two,three} > filename

1
“Echo” komutunu kullanırken modun neden fazladan alan gördüğünü açıkladığınız için teşekkür ederiz. Bu cevap bash betiğinde de (interaktif kabuk oturumunun aksine) iyi çalışıyor. Bunun gerçek cevap olduğunu ve kabul edilmiş bir cevap olması gerektiğini hissedin.
onelaview

1
Bu cevap kabul edilmelidir. Diğer tüm cevaplar OP'nin acısını çözmek için tonlarca ilginç başka yol sağladı, ancak teknik olarak soru "ekstra alan nasıl ortaya çıkıyor" ve hiç kimse bunu ele almadı! -1 gizemi yarattığın için teşekkürler Josh!
Dmitry Shevkoplyas

45

bir bash betiğinde aşağıdakiler çalışır:

#!/bin/sh

text="this is line one\nthis is line two\nthis is line three"
echo -e $text > filename

alternatif olarak:

text="this is line one
this is line two
this is line three"
echo "$text" > filename

kedi dosya adı verir:

this is line one
this is line two
this is line three

Shell Scripts sırasında alternatif hile çalışıyor gibi görünüyor, ancak bash için çalışmıyor gibi görünüyor.
Macindows

3
@Macindows için -eseçeneği unuttum gibi görünüyor echo. Lütfen tekrar deneyin.
Chris Maes

41

Her satırın düzgün bir şekilde girintili olmasını istediğimden daha fazla çözüm buldum:

  1. Şunları kullanabilirsiniz echo:

    echo    "this is line one"   \
        "\n""this is line two"   \
        "\n""this is line three" \
        > filename

    Bir satırın sonuna daha "\n"önce koyarsanız çalışmaz \.

  2. Alternatif olarak, printfdaha iyi taşınabilirlik için kullanabilirsiniz (çok fazla sorun yaşadım echo):

    printf '%s\n' \
        "this is line one"   \
        "this is line two"   \
        "this is line three" \
        > filename
  3. Yine başka bir çözüm olabilir:

    text=''
    text="${text}this is line one\n"
    text="${text}this is line two\n"
    text="${text}this is line three\n"
    printf "%b" "$text" > filename

    veya

    text=''
    text+="this is line one\n"
    text+="this is line two\n"
    text+="this is line three\n"
    printf "%b" "$text" > filename
  4. Başka bir çözüm, karıştırılarak elde edilir printfve sed.

    if something
    then
        printf '%s' '
        this is line one
        this is line two
        this is line three
        ' | sed '1d;$d;s/^    //g'
    fi

    Girinti seviyesini koda sabit olarak kodladığınız için böyle biçimlendirilmiş kodu yeniden düzenlemek kolay değildir.

  5. Bir yardımcı işlev ve bazı değişken ikame hileleri kullanmak mümkündür:

    unset text
    _() { text="${text}${text+
    }${*}"; }
    # That's an empty line which demonstrates the reasoning behind 
    # the usage of "+" instead of ":+" in the variable substitution 
    # above.
    _ ""
    _ "this is line one"
    _ "this is line two"
    _ "this is line three"
    unset -f _
    printf '%s' "$text"

3b, kod girintisini ve dize girintisini bağımsız olarak korumak istediğimde, en azından değişken atamada 2'yi kullanamadığımda ve 3a'dan daha okunabilir olduğunda, tercih edilen çözümdür. Umurumda değil zaman ben sadece alıntı dize birkaç satır üzerinde açık tutmak.
19'da Piz

Çok güzel cevap özellikle 3b
Sumit Trehan

Msgstr "Bir satırın sonuna" \ n "karakterini hemen \ koyarsanız çalışmaz." - yankı kullanırken harika bir ipucu .
Noam Manos

6

Aşağıdaki bir değişkene çok satırlı bir dize atamak için tercih edilen yoludur (Bence güzel görünüyor).

read -r -d '' my_variable << \
_______________________________________________________________________________

String1
String2
String3
...
StringN
_______________________________________________________________________________

Her iki durumda da alt çizgi sayısı aynıdır (burada 80).


0

Bazen yararlı olabileceğinden, tek satırlık basit bir birleşmeden bahsetmek gerekir.

# for bash

v=" guga "$'\n'"   puga "

# Just for an example.
v2="bar "$'\n'"   foo "$'\n'"$v"

# Let's simplify the previous version of $v2.
n=$'\n'
v3="bar ${n}   foo ${n}$v"

echo "$v3" 

Böyle bir şey alacaksın

bar 
   foo 
 guga 
   Puga 

Tüm önde gelen ve sona eren beyaz alanlar

echo "$v3" > filename

0

Bunu yapmanın birçok yolu var. Benim için, girintili diziyi sed'e borulamak güzel çalışıyor.

printf_strip_indent() {
   printf "%s" "$1" | sed "s/^\s*//g" 
}

printf_strip_indent "this is line one
this is line two
this is line three" > "file.txt"

Bu cevap Mateusz Piotrowski'nin cevabına dayanıyordu, ancak biraz rafine edildi.


-1

aşağıdaki gibi koyarsanız çalışacaktır:

AA='first line
\nsecond line 
\nthird line'
echo $AA
output:
first line
second line
third line
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.