Tekenreeks met meerdere regels met extra spatie (behouden inspringing)

Ik wil een aantal vooraf gedefinieerde teksten naar een bestand schrijven met het volgende:

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

Ik verwacht zoiets als dit:

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

Maar ik heb dit:

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

Ik weet zeker dat er geen spatie is na elke \n, maar hoe komt de extra spatie eruit?


Antwoord 1, autoriteit 100%

Heredoc klinkt handiger voor dit doel. Het wordt gebruikt om meerdere commando’s te sturen naar een commando-interpreterprogramma zoals exof cat

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

De tekenreeks na <<geeft aan waar te stoppen.

Om deze regels naar een bestand te sturen, gebruik je:

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

U kunt deze regels ook opslaan in een variabele:

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

Hiermee worden de regels opgeslagen in de variabele met de naam VAR.

Onthoud bij het afdrukken de aanhalingstekens rond de variabele, anders ziet u de tekens van de nieuwe regel niet.

echo "$VAR"

Nog beter, je kunt inspringen gebruiken om het meer op te laten vallen in je code. Voeg deze keer gewoon een -toe na <<om te voorkomen dat de tabbladen verschijnen.

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

Maar dan moet je tabs gebruiken, geen spaties, voor inspringing in je code.


Antwoord 2, autoriteit 30%

Als je de string in een variabele probeert te krijgen, is een andere gemakkelijke manier zoiets als dit:

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

Als u uw tekenreeks inspringt met tabs (d.w.z. ‘\t’), wordt de inspringing verwijderd. Als u inspringt met spaties, blijft de inspringing behouden.

OPMERKING: Het issignificant dat het laatste haakje sluiten op een andere regel staat. De tekst ENDmoet alleen op een regel verschijnen.


Antwoord 3, autoriteit 12%

echovoegt spaties toe tussen de argumenten die eraan worden doorgegeven. $textis onderhevig aan variabele uitbreiding en woordsplitsing, dus uw echo-opdracht is gelijk aan:

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

Je kunt zien dat er een spatie wordt toegevoegd voor “dit”. U kunt ofwel de tekens van de nieuwe regel verwijderen en $textciteren om de nieuwe regels te behouden:

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

Of je zou printfkunnen gebruiken, wat robuuster en draagbaarder is dan echo:

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

In bash, die brace-expansie ondersteunt, kunt u zelfs doen:

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

Antwoord 4, Autoriteit 7%

In een bash-script De volgende werken:

#!/bin/sh
text="this is line one\nthis is line two\nthis is line three"
echo -e $text > filename

alternatief:

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

Cat FileName geeft:

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

Antwoord 5, Autoriteit 5%

Ik heb meer oplossingen gevonden sinds ik elke regel op de juiste manier heb ingesprongen:

  1. U kunt echogebruiken:

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

    Het werkt niet als u "\n"vóór \aan het einde van een regel plaatst.

  2. U kunt ook gebruik maken van printfvoor een betere draagbaarheid (ik heb toevallig veel problemen met echo):

    printf '%s\n' \
        "this is line one"   \
        "this is line two"   \
        "this is line three" \
        > filename
    
  3. Nog een andere oplossing kan zijn:

    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
    

    of

    text=''
    text+="this is line one\n"
    text+="this is line two\n"
    text+="this is line three\n"
    printf "%b" "$text" > filename
    
  4. Een andere oplossing wordt bereikt door printfen sedte mengen.

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

    Het is niet eenvoudig om code die op deze manier is opgemaakt te refactoreren terwijl u het inspringingsniveau hardcodeert in de code.

  5. Het is mogelijk om een helperfunctie te gebruiken en enkele trucjes voor het vervangen van variabelen:

    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"
    

Antwoord 6

De volgende manier is mijn voorkeur om een string met meerdere regels aan een variabele toe te wijzen (ik vind het er mooi uitzien).

read -r -d '' my_variable << \
_______________________________________________________________________________
String1
String2
String3
...
StringN
_______________________________________________________________________________

Het aantal underscores is in beide gevallen hetzelfde (hier 80).


Antwoord 7

Ik kwam horen zoeken naar dit antwoord, maar wilde het ook naar een ander commando pijpen. Het gegeven antwoord is correct, maar als iemand het wil pijpen, moet je het pijpen vóór de multi-line-tekenreeks zoals deze

echo | tee /tmp/pipetest << EndOfMessage
This is line 1.
This is line 2.
Line 3.
EndOfMessage

Hiermee kunt u een multi-line-tekenreeks hebben, maar ook in de stdin van een volgende opdracht plaatsen.


Antwoord 8

Het werkt als u het hieronder legt:

AA='first line
\nsecond line 
\nthird line'
echo $AA
output:
first line
second line
third line

Antwoord 9

Om te vermelden een eenvoudige aaneenvoeging van één lijn omdat het soms nuttig kan zijn.

# 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" 

je krijgt zoiets

Bar
  foo
 guga
  puga

Alle toonaangevende en eindruimten worden voor

gecontroleerd

echo "$v3" > filename

Antwoord 10

Er zijn veel manieren om het te doen. Voor mij, de inspringende string in sed werkt mooi.

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"

Dit antwoord was gebaseerd op het antwoord van Mateusz Piotrowski, maar een beetje verfijnd.


Antwoord 11

Of tekst ingesprongen houden met spaties:

#!/bin/sh
sed 's/^[[:blank:]]*//' >filename <<EOF
    this is line one
    this is line two
    this is line three
EOF

Hetzelfde maar met een variabele:

#!/bin/sh
text="$(sed 's/^[[:blank:]]*//' << whatever
    this is line one
    this is line two
    this is line three
)"
echo "$text" > filename

😉

Other episodes