Se stai usando Bash, non devi nemmeno usare grep
:
files="*.jpg"
regex="[0-9]+_([a-z]+)_[0-9a-z]*"
for f in $files # unquoted in order to allow the glob to expand
do
if [[ $f =~ $regex ]]
then
name="${BASH_REMATCH[1]}"
echo "${name}.jpg" # concatenate strings
name="${name}.jpg" # same thing stored in a variable
else
echo "$f doesn't match" >&2 # this could get noisy if there are a lot of non-matching files
fi
done
È meglio mettere la regex in una variabile. Alcuni schemi non funzioneranno se inclusi letteralmente.
Questo utilizza =~
quale è l'operatore di corrispondenza regex di Bash. I risultati della partita vengono salvati in un array chiamato $BASH_REMATCH
. Il primo gruppo di acquisizione è memorizzato nell'indice 1, il secondo (se presente) nell'indice 2, ecc. L'indice zero è la corrispondenza completa.
Dovresti essere consapevole che senza ancore, questa regex (e quella che usa grep
) corrisponderà a uno dei seguenti esempi e altro, che potrebbe non essere quello che stai cercando:
123_abc_d4e5
xyz123_abc_d4e5
123_abc_d4e5.xyz
xyz123_abc_d4e5.xyz
Per eliminare il secondo e il quarto esempio, rendi il tuo regex in questo modo:
^[0-9]+_([a-z]+)_[0-9a-z]*
che dice che la stringa deve iniziare con una o più cifre. Il carato rappresenta l'inizio della stringa. Se aggiungi un segno di dollaro alla fine della regex, in questo modo:
^[0-9]+_([a-z]+)_[0-9a-z]*$
quindi anche il terzo esempio verrà eliminato poiché il punto non è tra i caratteri nella regex e il simbolo del dollaro rappresenta la fine della stringa. Nota che anche il quarto esempio fallisce questa corrispondenza.
Se hai GNU grep
(circa 2.5 o versioni successive, penso, quando l' \K
operatore è stato aggiunto):
name=$(echo "$f" | grep -Po '(?i)[0-9]+_\K[a-z]+(?=_[0-9a-z]*)').jpg
L' \K
operatore (look-behind a lunghezza variabile) fa corrispondere il modello precedente, ma non include la corrispondenza nel risultato. L'equivalente a lunghezza fissa è (?<=)
- il modello sarebbe incluso prima della parentesi di chiusura. È necessario utilizzare \K
se quantificatori possono corrispondere a stringhe di lunghezza diversa (ad esempio +
, *
, {2,4}
).
L' (?=)
operatore abbina schemi a lunghezza fissa o variabile e viene chiamato "look-ahead". Inoltre non include la stringa corrispondente nel risultato.
Al fine di rendere la corrispondenza senza distinzione tra maiuscole e minuscole, (?i)
viene utilizzato l' operatore. Colpisce i modelli che lo seguono, quindi la sua posizione è significativa.
Potrebbe essere necessario modificare la regex in base alla presenza di altri caratteri nel nome file. Noterai che in questo caso, mostro un esempio di concatenazione di una stringa mentre viene catturata la sottostringa.