Procesando bash variable con sed

16

La variable bash LATLNG contiene un valor de latitud y longitud entre paréntesis

(53.3096,-6.28396)

Quiero analizar estos en una variable llamada LAT y LON que estoy tratando de hacer a través de sed así

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

Sin embargo, me sale el siguiente error:

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

conorgriffin
fuente
1
Aprenda un lenguaje de secuencias de comandos como Python, Ruby, tal vez incluso PERL, para que no tenga que forzar al shell a hacer todo por usted. Incluso puede hacer que Javascript (Rhino) se ejecute en un sistema UNIX y casi todos necesitan saber algo de Javascript.
Michael Dillon
¿De dónde vienen estos valores? Sería más eficiente analizar los valores de latitud y longitud de la fuente original que agregar un paso adicional colocándolos en una bashvariable.
Kusalananda

Respuestas:

18

Esto se puede resolver a través de la sintaxis de shell puro. Sin embargo, requiere una variable temporal debido a los paréntesis (paréntesis):

#!/bin/bash

LATLNG="(53.3096,-6.28396)"

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

Alternativamente, puedes hacerlo de una vez jugando IFSy usando el readbuiltin:

#!/bin/bash

LATLNG="(53.3096,-6.28396)"

IFS='( ,)' read _ LAT LNG _ <<<"$LATLNG"
SiegeX
fuente
El primer ejemplo funcionará solo en bash, no en el shell POSIX.
gelraen
1
@gelraen de ahí el#!/bin/bash
SiegeX
Vea más expansiones aquí: gnu.org/software/bash/manual/…
Ricardo Stuven
22

La respuesta de SiegeX es mejor para este caso particular, pero también debe saber cómo pasar texto arbitrario sed.

sedespera nombres de archivo como su segundo, tercer, etc. parámetros, y si no encuentra ningún nombre de archivo, lee de su entrada estándar. Entonces, si tiene texto que desea procesar que no está en un archivo, debe canalizarlo sed. La forma más directa es esta:

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

Entonces su ejemplo sería:

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

Métodos alternativos (mejores pero más oscuros)

Si crees que hay alguna posibilidad de que $LATLNGcomience con un guión, o si quieres ser pedante, debes usar en printflugar de echo:

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

O un "documento aquí", pero eso puede ser un poco incómodo con la construcción que está utilizando:

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

O si está usando bashy no le preocupa la portabilidad, puede usar una "cadena aquí":

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

Aquí hay una solución que funcionará en cualquier 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"

Aquí hay otra solución igualmente portátil que analiza la sintaxis específica utilizada.

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- deja de ser malvado'
fuente
-1
LATLNG="(53.3096,-6.28396)"
set ${LATLNG//[(,)]/ }
LAT=$1
LON=$2
2nil
fuente
Probablemente deberías hacerlo set -- ...Hay una muy buena posibilidad de que el primer personaje sea un -.
mikeserv