Heredoc kann nicht so eingerückt werden, dass er mit dem Einzug des Nestings übereinstimmt


62

Wenn es ein "First World Problems" für das Scripting gibt, wäre dies das Richtige.

Ich habe den folgenden Code in einem Skript, das ich aktualisiere:

if [ $diffLines -eq 1 ]; then
        dateLastChanged=$(stat --format '%y' /.bbdata | awk '{print $1" "$2}' | sed 's/\.[0-9]*//g')

        mailx -r "Systems and Operations <sysadmin@[redacted].edu>" -s "Warning Stale BB Data" jadavis6@[redacted].edu <<EOI
        Last Change: $dateLastChanged

        This is an automated warning of stale data for the UNC-G Blackboard Snapshot process.
EOI

else
        echo "$diffLines have changed"
fi

Das Skript sendet E-Mails ohne Probleme, aber der Befehl mailx ist in einer if-Anweisung verschachtelt, sodass mir anscheinend zwei Möglichkeiten verbleiben:

  1. Setzen Sie EOIeine neue Zeile und brechen Sie die Einrückungsmuster oder
  2. Behalten Sie die Einrückung bei, aber verwenden Sie so etwas wie eine Echo-Anweisung, damit mailx meine E-Mails aufnimmt.

Ich bin offen für Alternativen zu heredoc, aber wenn es einen Weg gibt, dies zu umgehen, ist es meine bevorzugte Syntax.

Antworten:


113

Sie können den Here-Doc-Operator in ändern <<-. Sie können dann sowohl das Here-Doc als auch das Delimiter mit Tabulatoren einrücken:

#! /bin/bash
cat <<-EOF
    indented
    EOF
echo Done

Beachten Sie, dass Sie Tabulatoren und keine Leerzeichen verwenden müssen, um das Here-Doc einzurücken. Dies bedeutet, dass das obige Beispiel nicht kopiert werden kann (Stack Exchange ersetzt Tabulatoren durch Leerzeichen). Das erste EOFTrennzeichen darf nicht in Anführungszeichen gesetzt werden , da sonst die Parametererweiterung, die Befehlssubstitution und die arithmetische Erweiterung nicht wirksam sind.


Cool, das behebt das Einrückungsproblem, aber jetzt erweitert es nicht die Variable, die ich dort $dateLastChangedeinfügen möchte ( ), wenn ich in Ihrem Beispiel den Bindestrich + Anführungszeichen mache, sondern wenn ich den Bindestrich und die Anführungszeichen herausnehme und EOI auf a setze neue Zeile beginnt es wieder zu erweitern.
Bratchley

1
@ JoelDavis: Entfernen Sie einfach die Anführungszeichen, halten Sie den Bindestrich.
Choroba

5
Tabs benutzen zu müssen ist sehr ärgerlich. Gibt es einen guten Weg, das zu umgehen?
con-f-use

2
@ con-f-use: Du kannst sowas probieren cat << EOF | sed 's/^ *//'und so weiter.
Choroba

4
Oder noch besser: cat <<- EOF | awk 'NR==1 && match($0, /^ +/){n=RLENGTH} {print substr($0, n+1)}'. Dadurch wird die Anzahl der vorangestellten Leerzeichen in der ersten Zeile aus jeder Zeile des Here-Dokuments entfernt (dank anubhava ).
con-f-use

5

Wenn Sie in Ihrem Here-Dokument keine Befehlssubstitution und Parametererweiterung benötigen, können Sie die Verwendung von Tabulatoren vermeiden, indem Sie die führenden Leerzeichen zum Trennzeichen hinzufügen:

$     cat << '    EOF'
>         indented
>     EOF
        indented
$     cat << '    EOF' | sed -r 's/^ {8}//'
>         unindented
>     EOF
unindented

Ich konnte jedoch keine Möglichkeit finden, diesen Trick anzuwenden und die Parametererweiterung beizubehalten.


1
Für mich ist dies die einzige Antwort, die das Einrückungsproblem ohne Leerzeichen löst. shell-checkfindet alle Einrückungsänderungen, die nicht mit den Leerzeichen in der angegebenen Zeichenfolge übereinstimmen. Verwenden Sie doppelte Anführungszeichen für die Parametererweiterung?
Tom Hale

4

Versuche dies:

sed 's/^ *//' >> ~/Desktop/text.txt << EOF
    Load time-out reached and nothing to resume.
    $(date +%T) - Transmission-daemon exiting.
EOF

In diesem Fall können innerhalb des Heredocs keine unterschiedlich eingerückten Zeilen verwendet werden. (Dies ist wichtig, wenn der Inhalt beispielsweise ein Skript ist.)
ivan_pozdeev

2

Hmm ... Scheint, als könntest du das --formatArgument hier besser nutzen , um es --printfstattdessen zu verwenden und das Los einfach über ein Rohr zu leiten. Außerdem handelt es sich bei Ihrem if...fiBefehl um einen zusammengesetzten Befehl. Es kann eine Umleitung erforderlich sein, die von allen enthaltenen Befehlen übernommen wird, sodass Sie den heredoc möglicherweise überhaupt nicht verschachteln müssen.

if      [ "$diffLines" = 1 ]
then    stat --printf "Last Change: %.19y\n\n$(cat)\n" /.bbdata |
        mailx   -r  "Systems and Operations <sysadmin@[redacted].edu>" \
                -s  "Warning Stale BB Data" 'jadavis6@[redacted].edu'
else    echo    "$diffLines have changed"
fi      <<\STALE
This is an automated warning of stale data for the UNC-G Blackboard Snapshot process.
STALE

Ja, meine vorherige Überarbeitung sagte, dass mir der sed/ awkTeil nichts ausmacht . Ein Teil meiner heutigen Überarbeitung bestand darin, es herauszunehmen, da es für die Frage nicht von Belang war. So oder so ist es sechs von einem halben Dutzend des anderen.
Bratchley

@Bratchley - verdammt. Dieser letzte Satz wird mich für den Rest des Tages ablenken.
mikeserv

Wie meinst Du das?
Bratchley

1
@Bratchley - Sieht aus wie ein Rätsel.
mikeserv

Ha. Ich bin mir nicht sicher, aus welchem ​​Land du kommst, aber das ist in den USA eine gängige Redewendung. Bedeutet nur "unterschiedliche Herangehensweise an dasselbe Ziel". Ihre Lösung umgeht jedoch heredoc.
Bratchley

0

Die andere Methode wäre Herestrings:

    mail_content="Last Change: $dateLastChanged

    This is an automated warning of stale data for the UNC-G Blackboard Snapshot process."
    mailx -r "Systems and Operations <sysadmin@[redacted].edu>" -s "Warning Stale BB Data" jadavis6@[redacted].edu <<<"$mail_content"
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.