1114 Stimmen

Teilstring in Bash extrahieren

Angesichts eines Dateinamens in der Form someletters_12345_moreleters.ext Ich möchte die 5 Ziffern extrahieren und sie in eine Variable einfügen.

Um das zu verdeutlichen, habe ich einen Dateinamen mit einer Anzahl von x Zeichen, dann eine fünfstellige Sequenz, die von einem einzelnen Unterstrich auf beiden Seiten umgeben ist, und dann eine weitere Reihe von x Zeichen. Ich möchte die fünfstellige Zahl nehmen und sie in eine Variable einfügen.

Ich bin sehr daran interessiert, wie viele verschiedene Möglichkeiten es gibt, dies zu erreichen.

38voto

jperelli Punkte 6531

Für den Fall, dass jemand genauere Informationen wünscht, kann man auch wie folgt in man bash suchen

$ man bash [press return key]
/substring  [press return key]
[press "n" key]
[press "n" key]
[press "n" key]
[press "n" key]

Ergebnis:

${parameter:offset}
       ${parameter:offset:length}
              Substring Expansion.  Expands to  up  to  length  characters  of
              parameter  starting  at  the  character specified by offset.  If
              length is omitted, expands to the substring of parameter  start
              ing at the character specified by offset.  length and offset are
              arithmetic expressions (see ARITHMETIC  EVALUATION  below).   If
              offset  evaluates  to a number less than zero, the value is used
              as an offset from the end of the value of parameter.  Arithmetic
              expressions  starting  with  a - must be separated by whitespace
              from the preceding : to be distinguished from  the  Use  Default
              Values  expansion.   If  length  evaluates to a number less than
              zero, and parameter is not @ and not an indexed  or  associative
              array,  it is interpreted as an offset from the end of the value
              of parameter rather than a number of characters, and the  expan
              sion is the characters between the two offsets.  If parameter is
              @, the result is length positional parameters beginning at  off
              set.   If parameter is an indexed array name subscripted by @ or
              \*, the result is the length members of the array beginning  with
              ${parameter\[offset\]}.   A  negative  offset is taken relative to
              one greater than the maximum index of the specified array.  Sub
              string  expansion applied to an associative array produces unde
              fined results.  Note that a negative offset  must  be  separated
              from  the  colon  by  at least one space to avoid being confused
              with the :- expansion.  Substring indexing is zero-based  unless
              the  positional  parameters are used, in which case the indexing
              starts at 1 by default.  If offset  is  0,  and  the  positional
              parameters are used, $0 is prefixed to the list.

25voto

user1338062 Punkte 10425

Ich bin überrascht, dass diese reine Bash-Lösung nicht aufgetaucht ist:

a="someletters_12345_moreleters.ext"
IFS="_"
set $a
echo $2
# prints 12345

Wahrscheinlich möchten Sie IFS auf den vorherigen Wert zurücksetzen, oder unset IFS danach!

23voto

PEZ Punkte 16398

Aufbauend auf der Antwort von jor (die bei mir nicht funktioniert):

substring=$(expr "$filename" : '.*_\([^_]*\)_.*')

14voto

Wenn wir uns auf das Konzept der:
"Eine Reihe von (einer oder mehreren) Ziffern"

Wir können verschiedene externe Tools verwenden, um die Zahlen zu extrahieren.
Wir könnten ganz einfach alle anderen Zeichen löschen, entweder sed oder tr:

name='someletters_12345_moreleters.ext'

echo $name | sed 's/[^0-9]*//g'    # 12345
echo $name | tr -c -d 0-9          # 12345

Wenn $name jedoch mehrere Zahlenreihen enthält, schlägt das obige Verfahren fehl:

Wenn "name=someletters_12345_moreleters_323_end.ext", dann:

echo $name | sed 's/[^0-9]*//g'    # 12345323
echo $name | tr -c -d 0-9          # 12345323

Wir müssen reguläre Ausdrücke (regex) verwenden.
Um nur den ersten Lauf (12345 nicht 323) in sed und perl auszuwählen:

echo $name | sed 's/[^0-9]*\([0-9]\{1,\}\).*$/\1/'
perl -e 'my $name='$name';my ($num)=$name=~/(\d+)/;print "$num\n";'

Aber wir könnten es auch direkt tun in der Bash (1) :

regex=[^0-9]*([0-9]{1,}).*$; \
[[ $name =~ $regex ]] && echo ${BASH_REMATCH[1]}

Dies ermöglicht es uns, den ERSTEN Lauf von Ziffern beliebiger Länge zu extrahieren
umgeben von einem beliebigen anderen Text/Zeichen.

Nota : regex=[^0-9]*([0-9]{5,5}).*$; entspricht nur genau 5-stelligen Läufen :-)

(1) : schneller als der Aufruf eines externen Tools für jeden kurzen Text. Nicht schneller als die gesamte Verarbeitung in sed oder awk für große Dateien.

13voto

fedorqui Punkte 249453

Befolgung der Anforderungen

Ich habe einen Dateinamen mit einer Anzahl von x Zeichen und einer fünfstelligen Sequenz, umgeben von einem einzelnen Unterstrich auf jeder Seite, dann eine weitere Reihe von x Zeichen. Ich möchte die 5-stellige Zahl nehmen und in eine Variable einfügen.

Ich habe einige grep Möglichkeiten, die nützlich sein können:

$ echo "someletters_12345_moreleters.ext" | grep -Eo "[[:digit:]]+" 
12345

oder besser

$ echo "someletters_12345_moreleters.ext" | grep -Eo "[[:digit:]]{5}" 
12345

Und dann mit -Po Syntax:

$ echo "someletters_12345_moreleters.ext" | grep -Po '(?<=_)\d+' 
12345

Oder wenn Sie es auf genau 5 Zeichen bringen wollen:

$ echo "someletters_12345_moreleters.ext" | grep -Po '(?<=_)\d{5}' 
12345

Um die Daten in einer Variablen zu speichern, müssen Sie lediglich die var=$(command) Syntax.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X