Wie << EOF >> eine Datei mit Code katzen?

100

Ich möchte Code in eine Datei drucken mit cat <<EOF >>:

cat <<EOF >> brightup.sh
!/bin/bash
curr=`cat /sys/class/backlight/intel_backlight/actual_brightness`
if [ $curr -lt 4477 ]; then
   curr=$((curr+406));
   echo $curr  > /sys/class/backlight/intel_backlight/brightness;
fi
EOF

Aber wenn ich die Dateiausgabe überprüfe, erhalte ich Folgendes:

!/bin/bash
curr=1634
if [  -lt 4477 ]; then
   curr=406;
   echo   > /sys/class/backlight/intel_backlight/brightness;
fi

Ich habe versucht, einfache Anführungszeichen zu setzen, aber die Ausgabe enthält auch einfache Anführungszeichen. Wie kann ich dieses Problem vermeiden?

UberNate
quelle
2
Sie sollten auch den Schebang reparieren. Die erste Zeile muss buchstäblich #!/bin/bashund nichts anderes sein - das #!macht sie zu einer gültigen Shebang-Zeile, und was danach kommt, ist der Weg zum Dolmetscher.
Tripleee
1
sehen man bashund suchen nach Here Documents. Alle Details dort.
Hong
1
Abgesehen davon ist die moderne Syntax für die Prozessersetzung $(command)anstelle von `command`. Um den Inhalt einer Datei zu erhalten, hat Bash$(<file)
Tripleee

Antworten:

158

Sie brauchen nur eine minimale Änderung; Setzen Sie das Here-Document-Trennzeichen nach <<.

cat <<'EOF' >> brightup.sh

oder gleichwertig Backslash-Escape:

cat <<\EOF >>brightup.sh

Ohne Anführungszeichen wird das Dokument hier variabel ersetzt, Backticks werden ausgewertet usw., wie Sie festgestellt haben.

Wenn Sie einige, aber nicht alle Werte erweitern müssen, müssen Sie die Werte, die Sie verhindern möchten, einzeln umgehen.

cat <<EOF >>brightup.sh
#!/bin/sh
# Created on $(date # : <<-- this will be evaluated before cat;)
echo "\$HOME will not be evaluated because it is backslash-escaped"
EOF

wird herstellen

#!/bin/sh
# Created on Fri Feb 16 11:00:18 UTC 2018
echo "$HOME will not be evaluated because it is backslash-escaped"

Wie von @fedorqui vorgeschlagen , ist hier der relevante Abschnitt von man bash:

Hier Dokumente

Diese Art der Umleitung weist die Shell an, Eingaben von der aktuellen Quelle zu lesen, bis eine Zeile angezeigt wird, die nur ein Trennzeichen (ohne nachgestellte Leerzeichen) enthält. Alle bis zu diesem Punkt gelesenen Zeilen werden dann als Standardeingabe für einen Befehl verwendet.

Das Format der Here-Dokumente ist:

      <<[-]word
              here-document
      delimiter

Für Word wird keine Parametererweiterung, Befehlssubstitution, arithmetische Erweiterung oder Pfadnamenerweiterung durchgeführt. Wenn Zeichen in Wörtern in Anführungszeichen gesetzt werden, ist das Trennzeichen das Ergebnis der Entfernung von Anführungszeichen in Word, und die Zeilen im Dokument hier werden nicht erweitert. Wenn das Wort nicht in Anführungszeichen gesetzt ist, werden alle Zeilen des hier beschriebenen Dokuments einer Parametererweiterung, einer Befehlssubstitution und einer arithmetischen Erweiterung unterzogen . Im letzteren Fall wird die Zeichenfolge \ ignoriert und \ muss verwendet werden, um die Zeichen \, $ und `in Anführungszeichen zu setzen.

Tripleee
quelle
Ich sehe Sie markiert Wie vermeide ich , dass Heredoc Variablen erweitert? als Duplikat von diesem. Keine Einwände, nur, dass ich die Bash-Dokumentreferenz einschließen würde, wie ich es in meiner getan habe (die mit nur 13.000 Besuchen fast 100 Wiederholungen hatte, also scheint es ziemlich hilfreich zu sein).
Fedorqui 'SO hör auf zu schaden'
@fedorqui Vielleicht möchten Sie Ihre Antwort auf diese Frage tatsächlich portieren? Oder wir können die doppelte Markierung so umschalten, dass sie umgekehrt ist. Ich habe mir nur die Frage-Punktzahl angesehen, nicht die Antwort-Punktzahl.
Tripleee
Mmm , was zu verschmelzen sie, mit diesen ein als die Zielfrage? Die doppelte Frage hat einen guten Titel, nur dass sie zu lang ist. Allerdings hat es in letzter Zeit irgendwie ziemlich viel Aufmerksamkeit bekommen (ich bekomme einige positive Stimmen pro Monat ).
Fedorqui 'SO hör auf zu schaden'
@fedorqui Ich mag das Konzept des Zusammenführens, aber ich habe es in der Praxis noch nie gesehen. Wenn ich die Situation richtig verstehe, sind die Mods einfach nicht in der Lage, nicht triviale Zusammenführungen zu verarbeiten, da die Probleme und Komplexitäten die Vorteile bei weitem überwiegen. Was ich ein- oder zweimal getan habe, ist, eine nützliche und positiv bewertete Antwort zu löschen und sie unter einer anderen Frage erneut zu veröffentlichen, obwohl ich diese Problemumgehung kaum empfehlen kann.
Tripleee
Es ist schwer zu sagen, wann es sich lohnt. Ich habe es auf einer Seite gemacht, die ich modifiziert habe, als eine gute Frage gepostet wurde, ohne zu bemerken, dass es eine andere gute von zuvor gab, beide hatten gute Antworten. Das Entfernen meiner Antwort mit mehr als 90 Punkten scheint kein guter Plan zu sein, da diese Frage verwaist wäre.
Fedorqui 'SO hör auf zu schaden'
20

Oder Sie müssen Ihre EOF-Marker verwenden, um den anfänglichen Marker anzugeben, damit keine Erweiterung durchgeführt wird:

#-----v---v------
cat <<'EOF' >> brightup.sh
#!/bin/bash
curr=`cat /sys/class/backlight/intel_backlight/actual_brightness`
if [ $curr -lt 4477 ]; then
   curr=$((curr+406));
   echo $curr  > /sys/class/backlight/intel_backlight/brightness;
fi
EOF

IHTH

Shellter
quelle
1
Ich würde Ihren Beitrag bearbeiten, aber um sicher zu gehen, sollte es nicht #! / Bin / bash und nicht! / Bin / bash sein?
Matthew Hoggan
@MatthewHoggan: Ja, du hast recht! Danke, dass du das verstanden hast. Ich repariere es jetzt.
Shellter
15

Dies sollte funktionieren, ich habe es nur getestet und es hat wie erwartet funktioniert: Es fand keine Erweiterung, Substitution oder was-hast-du stattgefunden.

cat <<< '
#!/bin/bash
curr=`cat /sys/class/backlight/intel_backlight/actual_brightness`
if [ $curr -lt 4477 ]; then
  curr=$((curr+406));
  echo $curr  > /sys/class/backlight/intel_backlight/brightness;
fi' > file # use overwrite mode so that you don't keep on appending the same script to that file over and over again, unless that's what you want. 

Die Verwendung der folgenden Funktionen funktioniert ebenfalls.

cat <<< ' > file
 ... code ...'

Es ist auch erwähnenswert, dass bei der Verwendung von Heredocs wie << EOFSubstitution und variable Expansion und dergleichen stattfindet. Also mache so etwas:

cat << EOF > file
cd "$HOME"
echo "$PWD" # echo the current path
EOF

führt immer zur Erweiterung der Variablen $HOMEund $PWD. Wenn sich Ihr Home-Verzeichnis /home/foobarund der aktuelle Pfad befinden /home/foobar/bin, filesieht dies folgendermaßen aus:

cd "/home/foobar"
echo "/home/foobar/bin"

anstelle der erwarteten:

cd "$HOME"
echo "$PWD"
Alexej Magura
quelle
2
Eine Here-Zeichenfolge in einfachen Anführungszeichen darf offensichtlich keine einfachen Anführungszeichen enthalten, was ein unerschwingliches Problem sein kann. Hier sind Dokumente die einzig vernünftige Problemumgehung, wenn Sie ein Skript haben, das sowohl einfache als auch doppelte Anführungszeichen enthalten muss, obwohl dies beim einfachen Beispiel des OP natürlich nicht der Fall ist. Tangential gesehen sind Here-Strings <<<nur ab Bash 3 verfügbar und nicht auf andere Shells übertragbar.
Tripleee
<<<ist auch verfügbar in Zsh
Alexej Magura
3
Heute habe ich erfahren, dass Sie den Dateinamen unmittelbar nach der Eröffnung des Heredocs haben können. Danke @AlexejMagura!
Chaseadamsio