Verwenden der Ausgabe von Ausdrücken beim Bash-String-Slicing

Verwenden der Ausgabe von Ausdrücken beim Bash-String-Slicing

Ich möchte eine Teilzeichenfolge eines Dateinamens aus einem Pfad unbekannter Länge extrahieren. Ich kann diese beiden Teile separat ausführen, aber ich frage mich, ob es eine Möglichkeit gibt, die beiden ohne temporäre Variable zu kombinieren?

INPUT_PATH=/path/to/subfolder/file_17.txt 
# I would like to extract "17", the filname will always be 'file_XX.txt'
# The subfolder name is variable length 

TMP=$(basename ${INPUT_PATH})
FILE_NUMBER=${TMP:5:2}
echo ${FILE_NUMBER} # This works as expected

Ich habe es versucht ${$(basename $INPUT_PATH):5:2}, aber es tritt ein fehlerhafter Ersetzungsfehler auf. Gibt es einen Trick, um das zu beheben?

Antwort1

Einen anderen Ansatz für das Problem wählen und eine einzeilige Lösung anbieten, die nur bashdie Funktionalität nutzt:

$ cat demo.sh
#!/bin/bash

INPUT_PATH=/path/to/subfolder/file_17.txt

FILE_NUMBER=${INPUT_PATH:((${#INPUT_PATH} -6)):2}
echo ${FILE_NUMBER}
$

$./demo.sh
17

Ein einfacherer Ansatz wäre, vom Ende der Zeichenfolge rückwärts zu zählen, d. h.

FILE_NUMBER=${INPUT_PATH: -6:2}

Offensichtlich hängt diese Lösung davon ab, dass die Zeichenfolgenvariable mit „##XXXX“ endet, wobei „##“ die beiden relevanten Ziffern und „XXXX“ die letzten 4 Zeichen der Zeichenfolge sind.

Antwort2

Da Sie Bash verwenden, können Sie Regex-Matching nutzen:

if [[ $input =~ ([[:digit:]]+)\.txt$ ]]; then
    file_num=${BASH_REMATCH[1]}
fi

Antwort3

Am einfachsten ist es, FILE_NUMBER anstelle von TMP zu verwenden:

FILE_NUMBER=$(basename ${INPUT_PATH})
FILE_NUMBER=${FILE_NUMBER:5:2}

Außerdem ist die Verwendung der Parametererweiterung schneller als der Aufruf von basename:

FILE_NUMBER=${INPUT_PATH##*/}
FILE_NUMBER=${FILE_NUMBER:5:2}

Sie können sed verwenden, um alles in einer einzigen Zeile zu erledigen, aber das ist langsamer und weniger lesbar:

FILE_NUMBER=$(sed 's|.*/||;s/.....\(..\).*/\1/' <<<"$INPUT_PATH")

Antwort4

Für diejenigen, die zshanstelle von verwenden bash:

  • 6. bis 7. Zeichen derSchwanz(von zurückgegebener Teil basename) eines Pfades:

    num=${${a_path:t}[6,7]}
    

    ( $var:tvon cshum die tKrankheit zu bekommen)

    Sie können aus Kompatibilitätsgründen auch num=${"$(basename -- "$a_path")":5:2}den ksh93 ${var:offset:length}Operator verwenden, der kürzlich hinzugefügt wurde zsh. Die Befehlsersetzung muss in Anführungszeichen gesetzt werden, damit kein Array entsteht, sodass :5:2ein Zeichenbereich statt eines Bereichs von Array-Elementen ausgewählt wird. Die Verwendung der Befehlsersetzung und -ausführung basenamewäre jedoch weniger effizient und weniger zuverlässig als die Verwendung zshdes integrierten :tOperators.

  • erste Ziffernfolge in derSchwanz:

    num=${(MS)${a_path:t}##<->}
    

    ${var##pattern}ist der KSH-Operator, der den längsten führenden String entfernt, der mit pattern„von“ übereinstimmt $var. Mit dem MFlag Mwird der angehängte Teil zurückgegeben, anstatt entfernt zu werden, und Ses wird nach SUnterstrings gesucht, nicht nur am Anfang. Und <->es stimmt mit jeder Ziffernfolge überein ( <x-y>mit nicht angegebenen Grenzen).

  • Ziffernfolge nach a _imSchwanz:

    num=${${a_path:t}/(#m)*_(<->)*/$match[1]}
    

    (benötigt extendedglob; Vorsicht, es gibt das vollständige Ende zurück, wenn kein _digitsin vorhanden ist $a_path).

    Oder:

    [[ $a_path:t =~ '_([[:digit:]]+)' ]] && num=$match[1]
    

verwandte Informationen