Traitement de la variable bash avec sed

16

la variable bash LATLNG contient une valeur de latitude et de longitude entre parenthèses comme ceci

(53.3096,-6.28396)

Je veux les analyser dans une variable appelée LAT et LON que j'essaie de faire via sed comme ça

LAT=$(sed "s/(\(.*\),\(.*\))/\1/g" "$LATLNG")
LON=$(sed "s/(\(.*\),\(.*\))/\2/g" "$LATLNG")

Cependant, j'obtiens l'erreur suivante:

sed: can't read (53.3096,-6.28396): No such file or directory

conorgriffin
la source
1
Apprenez un langage de script comme Python, Ruby, peut-être même PERL, pour que vous n'ayez pas à forcer le shell à tout faire pour vous. Vous pouvez même faire fonctionner Javascript (Rhino) sur un système UNIX et presque tout le monde a besoin de connaître Javascript.
Michael Dillon
D'où viennent ces valeurs? Il serait plus efficace d'analyser les valeurs de latitude et de longitude à partir de la source d'origine que d'ajouter une étape supplémentaire en les mettant dans une bashvariable.
Kusalananda

Réponses:

18

Cela peut être résolu via une syntaxe de shell pure. Cependant, il nécessite une variable temporaire en raison des parenthèses (crochets):

#!/bin/bash

LATLNG="(53.3096,-6.28396)"

tmp=${LATLNG//[()]/}
LAT=${tmp%,*}
LNG=${tmp#*,}

Alternativement, vous pouvez le faire en une seule fois en jouant avec IFSet en utilisant la fonction readintégrée:

#!/bin/bash

LATLNG="(53.3096,-6.28396)"

IFS='( ,)' read _ LAT LNG _ <<<"$LATLNG"
SiegeX
la source
Le premier exemple ne fonctionnera qu'en bash, pas en shell POSIX.
gelraen
1
@gelraen d'où le#!/bin/bash
SiegeX
Voir plus d'extensions ici: gnu.org/software/bash/manual/…
Ricardo Stuven
22

La réponse de SiegeX est meilleure pour ce cas particulier, mais vous devez également savoir comment transmettre du texte arbitraire à sed.

sedattend les noms de fichiers comme ses deuxième, troisième, etc. paramètres, et s'il ne trouve aucun nom de fichier, il lit à partir de son entrée standard. Donc, si vous avez du texte à traiter qui n'est pas dans un fichier, vous devez le diriger vers sed. La façon la plus simple est la suivante:

echo "blah blah" | sed 's/blah/blam/g'

Votre exemple deviendrait donc:

LAT=$(echo "$LATLNG" | sed 's/(\(.*\),\(.*\))/\1/g')
LON=$(echo "$LATLNG" | sed 's/(\(.*\),\(.*\))/\2/g')

Méthodes alternatives (meilleures mais plus obscures)

Si vous pensez qu'il y a une chance qui $LATLNGpourrait commencer par un tiret, ou si vous voulez être pédant, vous devriez utiliser à la printfplace deecho :

printf '%s' "$LATLNG" | sed 's/foo/bar/g'

Ou un "document ici", mais cela peut être un peu gênant avec la construction que vous utilisez:

LAT=$(sed 's/foo/bar/g' <<END
$LATLNG
END
)

Ou si vous utilisez bashet ne vous inquiétez pas de la portabilité, vous pouvez utiliser une "chaîne ici":

sed 's/foo/bar/g' <<< "$LATLNG"
Jander
la source
3

Voici une solution qui fonctionnera dans n'importe quel shell POSIX:

parse_coordinates () {
  IFS='(), '  # Use these characters as word separators
  set -f      # Disable globbing
  set $1      # Split $1 into separate words
  set +f      # Restore shell state
  unset IFS
  LAT=$2      # $1 is the empty word before the open parenthesis
  LON=$3
}
parse_coordinates "$LATLNG"

Voici une autre solution tout aussi portable qui analyse la syntaxe spécifique utilisée.

LAT=${LATLNG%\)}    # strip final parenthesis
LAT=${LAT#\(}       # strip initial parenthesis
LON=${LAT##*[, ]}   # set LON to everything after the last comma or space
LAT=${LAT%%[, ]*}   # set LAT to everything before the first comma or space
Gilles 'SO- arrête d'être méchant'
la source
-1
LATLNG="(53.3096,-6.28396)"
set ${LATLNG//[(,)]/ }
LAT=$1
LON=$2
2nil
la source
Vous devriez probablement le faire. set -- ...Il y a de fortes chances que le premier personnage soit un -.
mikeserv