Comment extraire des parties d'une chaîne en variables?

8

J'ai une ligne d'un fichier comme celui-ci:

attempting to create a 512^3 level (with Dirichlet BC) using a 16^3 grid of 32^3 boxes and 800 tasks...

Je veux extraire le 512^3, 16^3, 32^3et 800quatre numéros et de les attribuer respectivement à quatre variables level, grid, boxeset taskspour une autre utilisation.

Comment puis-je faire ceci?

Yulong Ao
la source
Oui, les trois premiers ont le format a ^ b et le dernier juste un numéro habituel.
Yulong Ao

Réponses:

15

Bash peut faire correspondre des expressions régulières avec l' =~opérateur dans [[ ... ]]:

#! /bin/bash

line='attempting to create a 512^3 level (with Dirichlet BC) using a 16^3 grid of 32^3 boxes and 800 tasks...'
num='([0-9^]+)'
nonum='[^0-9^]+'
if [[ $line =~ $num$nonum$num$nonum$num$nonum$num ]] ; then
    level=${BASH_REMATCH[1]}
    grid=${BASH_REMATCH[2]}
    boxes=${BASH_REMATCH[3]}
    tasks=${BASH_REMATCH[4]}
    echo "Level $level, grid $grid, boxes $boxes, tasks $tasks."
fi
choroba
la source
2
Wow, je ne savais pas que Bash pouvait faire quelque chose comme ça :)
Erathiel
FYI 1: lors de l'écriture de l'expression rationnelle directement, ne le mettez pas entre guillemets . Par exemple, [[ 'Example 123' =~ '([0-9]+)' ]]est faux, mais [[ 'Example 123' =~ ([0-9]+) ]]fonctionne comme prévu.
Jonathan H
Pour info 2: la capture ne fonctionne pas plusieurs fois. Par exemple, [[ '1_2_3' =~ ([0-9]) ]] && echo ${BASH_REMATCH[@]}ne correspond qu'à 1.
Jonathan H
2

Utilisation de awk:

awk '{print "level="$5"\n""grid="$12"\n""boxes="$15"\n""tasks="$18}' file     
level=512^3
grid=16^3
boxes=32^3
tasks=800
jasonwryan
la source
2

Si cela provient d'un programme / script que vous avez écrit et que le texte est de formule (c'est-à-dire suit exactement ce modèle), vous pouvez simplement l'utiliser cut.

#!/bin/bash

$STRING='attempting to create a 512^3 level (with Dirichlet BC) using a 16^3 grid of 32^3 boxes and 800 tasks...'

level=$(echo $STRING | cut -d' ' -f5 -)
grid=$(echo $STRING | cut -d' ' -f12 -)
boxes=$(echo $STRING | cut -d' ' -f15 -)
tasks=$(echo $STRING | cut -d' ' -f18 -)
toxefa
la source
1

Si la ligne a toujours exactement cette structure, readpeut le faire sur une seule ligne sans processus externe:

read x x x x level x x x x x x grid x x boxes x x tasks x <<<"$line"

(en utilisant également une herestring ). Cela sauvera tous les mots qui ne vous intéressent pas x(à ignorer) et les valeurs que vous vouliez dans leurs variables respectives.

Michael Homer
la source