Ich habe gerade eine variable zugewiesen, aber echo $variable zeigt etwas anderes
Hier sind eine Reihe von Fällen, in denen echo $var
zeigen können, einen anderen Wert als das, was war gerade zugewiesen. Dies geschieht unabhängig davon, ob der zugewiesene Wert war "doppelte Anführungszeichen", 'single-quoted' oder ohne Anführungszeichen.
Wie bekomme ich die shell, um meine Variablen richtig?
Sternchen
Die erwartete Ausgabe ist /* Foobar is free software */
, aber stattdessen bekomme ich eine Liste der Dateinamen:
$ var="/* Foobar is free software */"
$ echo $var
/bin /boot /dev /etc /home /initrd.img /lib /lib64 /media /mnt /opt /proc ...
Eckigen Klammern
Dem erwarteten Wert ist [a-z]
, aber manchmal bekomme ich einen einzelnen Buchstaben, statt!
$ var=[a-z]
$ echo $var
c
Zeilenumbrüchen (newlines)
Dem erwarteten Wert ist eine Liste von separaten Linien, sondern alle Werte sind auf einer Linie!
$ cat file
foo
bar
baz
$ var=$(cat file)
$ echo $var
foo bar baz
Mehrere Räume
Erwartete ich ein sorgfältig ausgerichtet table-header, sondern mehrere Räume, die entweder verschwinden oder sind eingebrochen!
$ var=" title | count"
$ echo $var
title | count
Tabs
Erwartete ich zwei durch Tabulatoren getrennte Werte, aber stattdessen bekomme ich zwei Leerzeichen getrennte Werte!
$ var=$'key\tvalue'
$ echo $var
key value
var=$(cat file)
ist in Ordnung, aber echo "$var"
benötigt wird.BTW, das ist auch BashPitfalls #14: mywiki.wooledge.org/BashPitfalls#echo_.24foo
Siehe auch stackoverflow.com/questions/10067266/...
Auch, siehe auch stackoverflow.com/questions/2414150/...
InformationsquelleAutor that other guy | 2015-03-31
Du musst angemeldet sein, um einen Kommentar abzugeben.
In allen der oben genannten Fälle, wird die variable korrekt gesetzt, aber nicht richtig gelesen! Der richtige Weg ist, um doppelte Anführungszeichen verwenden bei der Referenzierung:
Dies gibt den erwarteten Wert in allen Beispielen gegeben. Immer zitieren variable Referenzen!
Warum?
Wenn eine variable ist nicht börsennotierten:
Unterziehen Feld aufteilen, wo der Wert wird aufgeteilt in mehrere Wörter am Leerzeichen (Standard):
Bevor:
/* Foobar is free software */
Nach:
/*
,Foobar
,is
,free
,software
,*/
Jedes dieser Wörter wird sich pathname-expansion, wo Muster erweitert werden, in den entsprechenden Dateien:
Bevor:
/*
Nach:
/bin
,/boot
,/dev
,/etc
,/home
, ...Schließlich werden alle Argumente übergeben echo, das schreibt Sie aus getrennt durch einzelne Leerzeichen, was
anstatt den Wert der Variablen.
Wenn die variable zitiert:
Dies ist, warum Sie sollten immer zitieren, alle Variablen Referenzen, es sei denn, Sie speziell benötigen word splitting-und Pfadnamen-expansion. Tools wie shellcheck sind da, um zu helfen, und warnt Sie über fehlende Zitate in allen Fällen vor.
InformationsquelleAutor that other guy
Möchten Sie vielleicht wissen, warum dies geschieht. Zusammen mit die große Erklärung von diesem anderen Kerl, finden Sie eine Referenz der Warum funktioniert mein shell-Skript choke auf Leerzeichen oder andere Sonderzeichen? geschrieben von Gilles in Unix & Linux:
InformationsquelleAutor fedorqui
Zusätzlich zu anderen verursachte Probleme nicht zu zitieren,
-n
und-e
verwendet werden könnenecho
als Argumente. (Nur der erste ist legal gemäß der POSIX-Spezifikation fürecho
, aber mehrere gemeinsame Implementierungen gegen die spec und verbrauchen-e
).Um dies zu vermeiden, verwenden
printf
stattecho
wenn details ankommt.Also:
Jedoch, korrekt zu zitieren wird nicht immer sparen Sie bei Verwendung
echo
:...in der Erwägung, dass es wird sparen Sie mit
printf
:-e
/-n
/backslash nicht angezeigt?" Wir können hinzufügen, die links von hier aus, als angemessen.Meinten Sie verbrauchen
-n
sowie?Nein, ich meinte
-e
. Der standard fürecho
nicht spezifiziert, ausgegeben, wenn das erste argument ist-n
, wodurch alle möglichen output-rechtlichen in diesem Fall; es gibt keine solche Bestimmung für-e
.Oh...ich kann es nicht Lesen. Lassen Sie uns die Schuld, mein Englisch. Danke für die Erklärung.
InformationsquelleAutor Charles Duffy
Benutzer doppelte Anführungszeichen, um den genauen Wert. wie diese:
und es zu Lesen Wert korrekt.
InformationsquelleAutor vanishedzhou
echo $var
Ausgabe hängt vom Wert derIFS
variable. Standardmäßig enthält er Leerzeichen, Tabulatoren und neue-Zeile-Zeichen:Dies bedeutet, dass wenn die shell tut field splitting (oder word-splitting) er verwendet alle diese Zeichen als Trennzeichen. Dies ist, was passiert, wenn auf eine variable ohne Anführungszeichen echo (
$var
) und damit die erwartete Ausgabe verändert wird.Einen Weg, um zu verhindern, dass word splitting (neben der Verwendung von doppelten Anführungszeichen) zu setzen, ist
IFS
auf null. Sehen http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_05 :Einstellung null Einstellung zu leeren
Wert:
Test:
set -f
zu verhindern Platzhalterist es wirklich notwendig für Ihre 1-st Beispiel mit Pfad expansion? Mit
IFS
auf null gesetzt,echo $var
erweitert werdenecho '/* Foobar is free software */'
und Pfad expansion erfolgt Sie nicht innerhalb von einfachen Anführungszeichen.Ja. Wenn Sie
mkdir "/this thing called Foobar is free software etc/"
du wirst sehen, dass es immer noch expandiert. Es ist natürlich praktischer für die[a-z]
Beispiel.Ich sehe, das macht Sinn für
[a-z]
Beispiel.InformationsquelleAutor ks1322
Zusätzliche, setzen Sie die variable in Anführungszeichen, man könnte auch übersetzen die Ausgabe der Variablen mit
tr
und konvertieren von Leerzeichen durch Zeilenumbrüche.Dies ist zwar ein wenig mehr gewundenen, es fügt mehr Vielfalt, mit dem Ausgang, als Sie ersetzen kann jedes Zeichen als Trennzeichen zwischen den array-Variablen.
Wahr, ja. Ich nehme an, es hängt davon ab, was in der variable. Ich benutze eigentlich
tr
die andere Weise herum zu erzeugen arrays aus Textdateien.Ein problem zu schaffen, indem Sie nicht unter Angabe der variable richtig und dann arbeiten, um es mit einem hamfisted extra Prozess ist nicht gut programmiert.
was? Es gibt keine
tr
benötigt, um richtig/korrekt ein array erstellen aus einer text-Datei können Sie die Trennzeichen angeben, was Sie wollen, indem Sie die Einstellung IFS. Zum Beispiel:IFS=$'\n' read -r -d '' -a arrayname < <(cat file.txt && printf '\0')
arbeitet den ganzen Weg zurück durch bash-3.2 (die älteste version in der breiten Zirkulation), und richtig setzt exit-status auf false, wenn Sie Ihrencat
gescheitert. Und wenn man wollte, sagen, tabs, anstatt Zeilenumbrüche, Sie würde Sie ersetzen nur die$'\n'
mit$'\t'
.Sie tun etwas, wie
arrayname=( $( cat file | tr '\n' ' ' ) )
dann kaputt auf mehreren Ebenen: Es ist zu Platzhaltern Ihrer Ergebnisse (also ein*
verwandelt sich in eine Liste der Dateien im aktuellen Verzeichnis), und es würde genauso gut funktionieren ohne dentr
(oder diecat
, für diese Angelegenheit; man konnte einfacharrayname=$( $(<file) )
und es würde gebrochen werden, in der gleichen Weise, aber weniger uneffektiv, so).InformationsquelleAutor Alek