Elegante Methode, um zu verhindern, dass durch das Ersetzen von Befehlen nachgestellte Zeilenumbrüche entfernt werden


7

Ich passe mein zsh an PROMPTund rufe eine Funktion auf, die echobasierend auf dem Status einer Umgebungsvariablen eine Zeichenfolge sein kann oder nicht :

function my_info {
    [[ -n "$ENV_VAR"]] && echo "Some useful information\n"
}

local my_info='$(my_info)'

PROMPT="${my_info}My awesome prompt $>"

Ich möchte, dass die Informationen in einer nachfolgenden neuen Zeile enden, damit sie, wenn sie festgelegt sind, in einer eigenen Zeile angezeigt werden:

Some useful information
My awesome prompt $>

Wenn es jedoch nicht festgelegt ist, soll sich die Eingabeaufforderung in einer einzelnen Zeile befinden, um eine leere Zeile zu vermeiden, die durch eine bedingungslose neue Zeile in meiner Eingabeaufforderung verursacht wird:

PROMPT="${my_info}  # <= Don't want that :)
My awesome prompt $>"

Derzeit arbeite ich daran $(command substitution), meine neue Zeile zu entfernen, indem ich sie mit einem nicht druckbaren Zeichen versehen muss, damit die neue Zeile nicht mehr nachläuft:

[[ -n "$ENV_VAR"]] && echo "Some useful information\n\r"

Dies ist offensichtlich ein Hack. Gibt es eine saubere Möglichkeit, eine Zeichenfolge zurückzugeben, die auf einer neuen Zeile endet?

Bearbeiten: Ich verstehe, was den Verlust der nachfolgenden Zeilenumbruch verursacht und warum dies geschieht , aber in dieser Frage möchte ich speziell wissen, wie dieses Verhalten verhindert werden kann (und ich glaube nicht, dass diese Problemumgehung in meinem Fall zutrifft, da ich es bin auf der Suche nach einer "bedingten" Newline).

Bearbeiten: Ich stehe korrigiert da: Die referenzierte Problemumgehung könnte tatsächlich eine ziemlich nette Lösung sein (da das Präfixieren von Zeichenfolgen in Vergleichen ein allgemeines und etwas ähnliches Muster ist), außer ich kann es nicht richtig zum Laufen bringen:

echo "Some useful information\n"x
  [...]
PROMPT="${my_info%x}My awesome prompt $>"

streift xmir nicht das Schleppen ab .

Bearbeiten: Das Anpassen der vorgeschlagenen Problemumgehung an die Verrücktheit, die eine sofortige Erweiterung bedeutet, hat bei mir funktioniert:

function my_info {
    [[ -n "$ENV_VAR"]] && echo "Some useful information\n"x
}

local my_info='${$(my_info)%x}'

PROMPT="$my_info My awesome prompt $>"

Sie sind der Richter, wenn dies eine bessere Lösung als die ursprüngliche ist. Es ist ein bisschen expliziter, denke ich, aber es fühlt sich auch etwas weniger lesbar an.



@ G-Man Auf den ersten Blick sieht es nicht so aus, als ob die superuser.com-Frage übereinstimmt, da die akzeptierte Antwort besagt, dass das Problem nicht bei der Befehlssubstitution liegt, sondern bei der nachfolgenden echoing. Was bei dieser Frage nicht der Fall ist.
dtk

D'oh! Du hast recht; Ich habe es zu schnell gelesen.
G-Man sagt "Reinstate Monica"

1
Wie ist diese Frage ein Duplikat von unix.stackexchange.com/questions/17732/… ? Diese Frage fragt, warum der Effekt auftritt und die akzeptierte Antwort erklärt ihn. Wie ich in meiner ersten Bearbeitung festgestellt habe, war mir diese Frage beim Posten dieser Frage bekannt, daher weiß ich, warum sie auftritt, aber sie beantwortet nicht, wie sie am besten verhindert werden kann.
dtk

Antworten:


4

Letzte Zeilenumbrüche werden aus Befehlsersetzungen entfernt. Selbst zsh bietet keine Option, um dies zu vermeiden. Wenn Sie also endgültige Zeilenumbrüche beibehalten möchten, müssen Sie dafür sorgen, dass es sich nicht um endgültige Zeilenumbrüche handelt.

Der einfachste Weg, dies zu tun, besteht darin, ein zusätzliches Zeichen (außer einem Zeilenumbruch) nach den Daten zu drucken, die Sie genau erhalten möchten, und dieses letzte zusätzliche Zeichen aus dem Ergebnis der Befehlsersetzung zu entfernen. Sie können optional eine neue Zeile nach diesem zusätzlichen Zeichen einfügen, die trotzdem entfernt wird.

In zsh können Sie die Befehlssubstitution mit der Zeichenfolgenmanipulation kombinieren, um das zusätzliche Zeichen zu entfernen.

my_info='${$(my_info; echo .)%.}'
PROMPT="${my_info}My awesome prompt $>"

Achten Sie in Ihrem Szenario darauf, dass dies my_infonicht die Ausgabe des Befehls ist, sondern ein Shell-Snippet, um die Ausgabe abzurufen, die ausgewertet wird, wenn die Eingabeaufforderung erweitert wird. PROMPT=${my_info%x}…hat nicht funktioniert, weil das versucht, ein Finale xaus dem Wert der my_infoVariablen zu entfernen , aber es endet mit ).

In anderen Shells muss dies in zwei Schritten erfolgen:

output=$(my_info; echo .)
output=${output%.}

In Bash könnten Sie nicht my_infodirekt von anrufen PS1; stattdessen müssten Sie es von anrufen PROMPT_COMMAND.

PROMPT_COMMAND='my_info=$(my_info; echo .)'
PS1='${my_info%.}…'

Beachten Sie, dass Sie setopt promptsubstin zsh benötigen ${variables}, damit diese in der Eingabeaufforderung erweitert werden.
Stéphane Chazelas

-1

Sie können Ihre Funktion die Escape-Escape-Codes ausgeben lassen, sodass sie beim Erweitern in die neue Zeile umgewandelt wird.

$ function my_info {
>    [[ -n "$ENV_VAR"]] && echo 'Some useful information\\n'
>}
$ echo $(my_info)
Some useful information

$

1
Ja, ich versuchte , dass (in verschiedenen Variationen, einschließlich dem zsh spezifischen $'\n'Mechanismus ), aber es funktioniert nicht, da zsh nicht dehnt die resultierend \nim PROMPTstring: /
dtk

Liegt das nicht an den einfachen Anführungszeichen in Ihrer Variablenzuweisung? local my_info='$(my_info)'? Versuchen Sie es ohne sie oder nurPROMPT="$(my_info) My awesome prompt $>"
spelufo

Nein, der zsh dehnt PROMPT="Foo\nBar"sich im Gegensatz zu nicht einmal aus $ ENV_VAR="Foo\nBar"; echo $ENV_VAR. Die einfachen Anführungszeichen in der Zuweisung werden benötigt, damit der Ausdruck nicht erweitert wird, wenn die Datei bezogen wird, da die "Referenz", die die Variable enthält, jedes Mal aufgelöst werden sollte, wenn die PROMPTVariable ausgewertet wird.
dtk
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.