Anzahl der Zeichen in der Ausgabe eines Shell-Befehls

Anzahl der Zeichen in der Ausgabe eines Shell-Befehls

Ich schreibe ein Skript, das die Anzahl der Zeichen in der Ausgabe eines Befehls berechnen muss inein einziger Schritt.

Beispielsweise readlink -f /etc/fstabsollte die Verwendung des Befehls zurückgeben 10, da die Ausgabe dieses Befehls 10 Zeichen lang ist.

Dies ist mit gespeicherten Variablen bereits mit dem folgenden Code möglich:

variable="somestring";
echo ${#variable};
# 10

Leider funktioniert die Verwendung derselben Formel mit einer durch einen Befehl generierten Zeichenfolge nicht:

${#(readlink -f /etc/fstab)};
# bash: ${#(readlink -f /etc/fstab)}: bad substitution

Ich verstehe, dass dies möglich ist, indem man zuerst die Ausgabe in einer Variablen speichert:

variable=$(readlink -f /etc/fstab);
echo ${#variable};

Aber ich möchte den zusätzlichen Schritt entfernen.

Ist das möglich? Kompatibilität mit der Almquist-Shell (sh) unter Verwendung nur integrierter oder standardmäßiger Dienstprogramme ist vorzuziehen.

Antwort1

MitGNU-Ausdruck:

$ expr length + "$(readlink -f /etc/fstab)"
10

Es +gibt eine spezielle Funktion von GNU, exprum sicherzustellen, dass das nächste Argument als Zeichenfolge behandelt wird, selbst wenn es sich um einen exprOperator wie match, length, +… handelt.

Das Obige entfernt alle nachfolgenden Zeilenumbrüche aus der Ausgabe. So umgehen Sie das Problem:

$ expr length + "$(readlink -f /etc/fstab; printf .)" - 2
10

Das Ergebnis wurde abgezogen zu2wegen des letzten Zeilenumbruchs readlinkund des Zeichens, das .wir hinzugefügt haben.

Bei Unicode-Strings exprscheint dies nicht zu funktionieren, da die Länge des Strings in Bytes statt in der Anzahl der Zeichen zurückgegeben wird (sieheLinie 654)

$ LC_ALL=C.UTF-8 expr length ăaa
4

Sie können also Folgendes verwenden:

$ printf "ăaa" | LC_ALL=C.UTF-8 wc -m
3

POSIXLY:

$ expr " $(readlink -f /etc/fstab; printf .)" : ".*" - 3
10

Das Leerzeichen vor der Befehlsersetzung verhindert, dass der Befehl mit der Zeichenfolge abstürzt, die mit beginnt. -Daher müssen wir 3 abziehen.

Antwort2

Ich bin nicht sicher, wie das mit integrierten Shell-Funktionen funktioniert (Gnouc ist allerdings), aber die Standardwerkzeuge können helfen:

  1. Sie können wc -mwhich verwenden, um Zeichen zu zählen. Leider zählt es auch den letzten Zeilenumbruch, sodass Sie diesen zuerst entfernen müssen:

    readlink -f /etc/fstab | tr -d '\n' | wc -m
    
  2. Sie können natürlichawk

    readlink -f /etc/fstab | awk '{print length($0)}'
    
  3. Oder Perl

    readlink -f /etc/fstab | perl -lne 'print length'
    

Antwort3

Normalerweise mache ich es so:

$ echo -n "$variable" | wc -m
10

Um Befehle auszuführen, würde ich es folgendermaßen anpassen:

$ echo -n "$(readlink -f /etc/fstab)" | wc -m
10

Dieser Ansatz ähnelt dem, was Sie in Ihren beiden Schritten getan haben, außer dass wir sie zu einer einzigen Zeile kombinieren.

Antwort4

Dies funktioniert, dasherfordert aber, dass die Zielvariable definitiv leer oder nicht gesetzt ist. Deshalb ist dies eigentlichzweiBefehle - ich leere ausdrücklich $lim ersten:

l=;printf '%.slen is %d and result is %s\n' \
    "${l:=$(readlink -f /etc/fstab)}" "${#l}" "$l"

AUSGABE

len is 10 and result is /etc/fstab

Das sind alles integrierte Shell-Funktionen – readlinknatürlich nicht einschließlich –, aber wenn Sie es auf diese Weise in der aktuellen Shell auswerten, bedeutet das, dass Sie die Zuweisung durchführen müssen, bevor Sie die Länge abrufen. Deshalb %.slösche ich das erste Argument in der printfFormatzeichenfolge und füge es einfach erneut für den Literalwert am Ende der printfArgumentliste von hinzu.

Mit eval:

l=$(readlink -f /etc/fstab) eval 'l=${#l}:$l'
printf %s\\n "$l"

AUSGABE

10:/etc/fstab

Sie können nahezu dasselbe erreichen, aber statt der Ausgabe in einer Variablen im ersten Befehl erhalten Sie sie auf stdout:

PS4='${#0}:$0' dash -cx '2>&1' "$(readlink -f /etc/fstab)"

...der schreibt...

10:/etc/fstab

...zum Dateideskriptor 1, ohne einer Variable in der aktuellen Shell einen Wert zuzuweisen.

verwandte Informationen