Ist es möglich, ANSI-Farb-Escape-Codes in Bash-Here-Dokumenten zu verwenden?

7

Ich drucke eine Nachricht in einem Bash-Skript und möchte einen Teil davon einfärben. zum Beispiel,

#!/bin/bash

normal='\e[0m'
yellow='\e[33m'
cat <<- EOF
    ${yellow}Warning:${normal} This script repo is currently located in:
    [ more messages... ]
EOF

Aber wenn ich im Terminal ( tmuxinnen gnome-terminal) laufe, werden die ANSI-Escape-Zeichen nur in \Form gedruckt . zum Beispiel,

\e[33mWarning\e[0m This scr....

Wenn ich den Teil, den ich einfärben möchte, in einen printfBefehl außerhalb des Here-Dokuments verschiebe, funktioniert dies. Zum Beispiel funktioniert dies:

printf "${yellow}Warning:${normal}"
cat <<- EOF
    This script repo is currently located in:
    [ more messages... ]
EOF

Von man bash- Hier Dokumente:

Für Word werden keine Parameter- und Variablenerweiterungen, Befehlssubstitutionen, arithmetischen Erweiterungen oder Pfadnamenerweiterungen ausgefü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 \ <newline> wird ignoriert und \muss verwendet werden , um die Zeichen zu zitieren \, $und `.

Ich kann nicht herausfinden, wie sich dies auf ANSI-Escape-Codes auswirken würde. Ist es möglich, ANSI-Escape-Codes in einem catausgeblendeten Bash-Here-Dokument zu verwenden?

the_velour_fog
quelle
Ich glaube nicht, dass dies etwas mit diesen Dokumenten zu tun hat. Ihre Variable enthält die Literalzeichenfolge \e[33mund wird in beiden Fällen normal ersetzt. Wenn Sie Grund zu der Annahme haben, dass es sich um Heredocs handelt, oder um einen echten Code, der das Verhalten zeigt, an dem Sie interessiert sind, bearbeiten Sie ihn bitte in.
Michael Homer
2
Entweder yellow=$'\e[33m'oder yellow=$(printf '\e[33m')(wie Sie es bereits tun) setzt das Escape-Zeichen direkt in die Zeichenfolge, um es zu testen.
Michael Homer
1
@MichaelHomer Also im Grunde ist die Zeichenfolge '\e[33m'für ein Terminal bedeutungslos? es hat nur Bedeutung für Befehle wie echo -eoder printf- die dann den "echten" Code erzeugen, der an das Terminal gesendet wird?
the_velour_fog
Ja.
Michael Homer

Antworten:

25

In Ihrem Skript diese Zuordnungen

normal='\e[0m'
yellow='\e[33m'

Setzen Sie diese Zeichen buchstäblich in die Variablen ein, dh \e[0mnicht in die Escape-Sequenz. Sie können ein Escape-Zeichen mit printf(oder einigen Versionen von echo) erstellen , z.

normal=$(printf '\033[0m')
yellow=$(printf '\033[33m')

Sie sollten es jedoch viel besser verwenden tput, da dies für jedes korrekt eingerichtete Terminal funktioniert:

normal=$(tput sgr0)
yellow=$(tput setaf 3)

Wenn Sie sich Ihr Beispiel ansehen, scheint es, dass die Version von printfIhnen Leckereien \eals Escape-Zeichen verwendet (was auf Ihrem System möglicherweise funktioniert, aber im Allgemeinen nicht auf andere Systeme portierbar ist). Versuchen Sie es, um dies zu sehen

yellow='\e[33m'
printf 'Yellow:%s\n' $yellow

und Sie würden die wörtlichen Zeichen sehen:

Yellow:\e[33m

eher als die Escape-Sequenz. Wenn Sie diese in das printfFormat einfügen printf, werden sie interpretiert (wenn dies möglich ist).

Weiterführende Literatur:

Thomas Dickey
quelle
Ich verstehe nicht, was Sie damit meinen , diese Zeichen buchstäblich in die Variablen zu setzen - ist es nicht das, was Sie wollen? dh die Variablen speichern nur die Werte, bis die Variablen in die Zeichenfolge interpoliert werden?
the_velour_fog
Dieses Format schien nicht zuverlässig zu funktionieren (das yellowfunktionierte nicht, aber das normaltat es). aber das normal=$(tput sgr0) format funktioniert einwandfrei!
the_velour_fog
1
ah ok, so printf 'Yellow:%s\n' $yellow produzierte wörtliche Zeichen, weil printfes keine Yellow"spezielle" Behandlung gab. Der Grund dafür printf "%s" "$(tput setaf 3)foo$(tput sgr0)"ist, dass tput Escape-Sequenzen generiert, die das Terminal direkt erkennen kann. Gut zu wissen, danke!
the_velour_fog
Auch red=$'\e[31m'in ksh93, bash, zsh, mksh, FreeBSD sh und bald POSIX.
Stéphane Chazelas
2

Bei diesen Zuweisungen werden keine maskierten Zeichen in die Variable eingefügt:

normal='\e[0m'                  yellow='\e[33m'

Dazu benötigen Sie echo -e printfoder $'...'(in Bash).

Da Sie bash verwenden, können Sie auch Folgendes verwenden:

normal=$'\e[0m'                 yellow=$'\e[33m'

Bitte beachten Sie die $vor der Zeichenfolge '\e[0m'.

Der tragbare Weg, um maskierte Zeichen zu erhalten, ist jedoch printf, wie folgt:

normal="$(printf '\033[0m')"    yellow="$(printf '\033[33m')"

Der Oktalwert (033) des Escapezeichens ist in allen POSIX-Shells gültig.


quelle
Beachten Sie, dass $'\e[0min der nächsten Haupt Ausgabe der POSIX - Spezifikation sein und wird bereits unterstützt in ksh93(wo es herkommt) bash, zsh, mkshund FreeBSD shzumindest.
Stéphane Chazelas
Beachten Sie, dass die echo -eAusgabe "-e\n" in POSIX-kompatiblen Echo-Implementierungen erfolgt. echo '\033'gibt ein ESC-Zeichen mit Unix-konformen echos auf ASCII-basierten Systemen aus.
Stéphane Chazelas
@ StéphaneChazelas Ich hatte den Eindruck, dass eine vernünftige Platzierung printfeine gute Lösung ist. Und dass die Verwendung von printf eine Möglichkeit war, die Präsentation, Diskussion und endgültige Ablehnung der Verwendung des echoBefehls " Fehlerhaftes in mehrfacher Hinsicht" zu vermeiden . Was macht es nützlich, echoin dieser Antwort auf den Befehl zu verweisen ?