Wie bekomme ich das Zeichen an einer bestimmten Position eines Strings in einem Shell-Skript?

21

Wie bekomme ich das Zeichen an einer bestimmten Position eines Strings in einem Shell-Skript?

Tom Brito
quelle

Antworten:

35

In der Bash mit "Parameter Expansion" $ {parameter: offset: length}

$ var=abcdef
$ echo ${var:0:1}
a
$ echo ${var:3:1}
d

Edit: Ohne Parametererweiterung (nicht sehr elegant, aber das ist mir zuerst eingefallen)

$ charpos() { pos=$1;shift; echo "$@"|sed 's/^.\{'$pos'\}\(.\).*$/\1/';}
$ charpos 8 what ever here
r
forcefsck
quelle
1
gnu.org/software/bash/manual/… hat weitere Details
jsbillings
Offenbar nicht POSIX: pubs.opengroup.org/onlinepubs/009695399/utilities/…
Ciro Santilli
Sie können den Versatz auch wie echo ${var: -2:1}
folgt
Diese Syntax stammt von ksh93 und wird auch von zshund unterstützt mksh.
Stéphane Chazelas
6

Alternative zur Parametererweiterung ist expr substr

substr STRING POS LENGTH
    substring of STRING, POS counted from 1

Beispielsweise:

$ expr substr hello 2 1
e
Dogbane
quelle
cool, sollte genauer überprüft werden.
Forcefsck
1
Dies scheint zwar mit dem Ausdruck von GNU coreutils zu funktionieren, substrist jedoch nicht in dem Ausdruck von FreeBSD, NetBSD oder OS X enthalten. Dies ist keine portable Lösung.
Ghoti
@ghoti, beachte, dass substres sich ursprünglich nicht um eine GNU-Erweiterung handelt. Die ursprüngliche Implementierung von exprkam von PWB Unix in den späten 70ern und hatte substr(aber nicht :).
Stéphane Chazelas
@ StéphaneChazelas, danke für das Hinzufügen der historischen Perspektive. :) Obwohl ich mir ziemlich sicher bin, dass die PWB-Nutzung für das OP nicht relevant ist, macht es immer Spaß, Funktionen und Änderungen über die Jahrzehnte hinweg zu verfolgen. GNU ist in der Regel die Standardeinstellung vieler Leute, aber im Allgemeinen würde ich die Verwendung von Optionen vermeiden, die nicht eindeutig POSIX sind und von denen bekannt ist, dass sie in großen Unices fehlen.
Ghoti
5

cut -c

Wenn die Variable keine Zeilenumbrüche enthält, können Sie Folgendes tun:

myvar='abc'
printf '%s\n' "$myvar" | cut -c2

Ausgänge:

b

awk substr ist eine weitere POSIX-Alternative, die auch dann funktioniert, wenn die Variable Zeilenumbrüche enthält:

myvar="$(printf 'a\nb\n')" # note that the last newline is stripped by
                           # the command substitution
awk -- 'BEGIN {print substr (ARGV[1], 3, 1)}' "$myvar"

Ausgänge:

b

printf '%s\n'soll Probleme mit Escape-Zeichen vermeiden: /programming//a/40423558/895245 zB:

myvar='\n'
printf '%s\n' "$myvar" | cut -c1

Ausgänge \wie erwartet.

Siehe auch: /programming/1405611/extracting-first-two-characters-of-a-string-shell-scripting

Getestet in Ubuntu 19.04.

Ciro Santilli ist ein Schauspieler
quelle
printf '%s' "$myvar" | cut -c2ist nicht POSIX, da die Ausgabe von printfkein Text ist, es sei denn, sie $myvarendet in einem Zeilenumbruch. Er geht davon aus sonst die Variable enthält keine Zeilenumbrüche wie cutschneidet jede Zeile seiner Eingabe.
Stéphane Chazelas
Die awkeine wäre effizienter und zuverlässiger mitawk -- 'BEGIN {print substr (ARGV[1], 2, 1)}' "$myvar"
Stéphane Chazelas
Beachten Sie, dass dies mit aktuellen GNU-Versionen cutnicht für Multi-Byte-Zeichen funktioniert (dasselbe gilt für mawk oder busybox awk)
Stéphane Chazelas,
@Stéphanechazelas danke für die punkte. Ich habe im ersten nicht verstanden, was Sie meinen: Meinst du, das printf 'abc '| cut -c2ist falsch, weil nein \n(das weiß ich nicht), oder dass der Befehl fehlschlägt, wenn myvar Zeilenumbrüche enthält (dem stimme ich zu)?
Ciro Santilli
1
Das Verhalten von cutist nicht spezifiziert, wenn die Eingabe kein Text ist (obwohl cutImplementierungen erforderlich sind, um Zeilen oder eine beliebige Länge zu verarbeiten). Die Ausgabe von printf abcist kein Text, da sie nicht in einem Zeilenumbruch endet. In der Praxis je nach Implementierung, wenn Sie Rohr , das zu cut -c2, Sie entweder b, b<newline>oder gar nichts. Sie müssten printf 'abc\n' | cut -c2ein von POSIX festgelegtes Verhalten erhalten (das für die Ausgabe erforderlich ist b<newline>)
Stéphane Chazelas,
1

Mit zshoder würden yashSie Folgendes verwenden:

$ text='€$*₭£'
$ printf '%s\n' "${text[3]}"
*

(In zsh, Sie können es zu kürzen printf '%s\n' $text[3]).

Stéphane Chazelas
quelle
0

Sie können den Befehl Ausschneiden verwenden. So erhalten Sie die 3. Position:

echo "SAMPLETEXT" | cut -c3

Überprüfen Sie diesen Link http://www.folkstalk.com/2012/02/cut-command-in-unix-linux-examples.html

( Fortgeschrittene Fälle ) Das Ändern von IFS ist jedoch auch eine gute Sache, insbesondere wenn Ihre Eingabe möglicherweise Leerzeichen enthält. Verwenden Sie in diesem Fall nur den folgenden

saveifs=$IFS
IFS=$(echo -en "\n\b")
echo "SAMPLETEXT" | cut -c3
IFS=$saveifs
Midhun Jose
quelle
Ich kann nicht sehen, wie IFSder von Ihnen gepostete Code ins Spiel kommen würde.
Kusalananda