Processando variável bash com sed


16

variável bash LATLNG contém um valor de latitude e longitude entre parênteses como

(53.3096,-6.28396)

Eu quero analisá-los em uma variável chamada LAT e LON, que estou tentando fazer via sed assim

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

No entanto, eu recebo o seguinte erro:

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


1
Aprenda uma linguagem de script como Python, Ruby, talvez até PERL, para que você não precise forçar o shell a fazer tudo por você. Você pode até fazer o Javascript (Rhino) rodar em um sistema UNIX e quase todo mundo precisa saber um pouco de Javascript.
Michael Dillon

De onde vêm esses valores? Seria mais eficiente analisar os valores de latitude e longitude da fonte original do que adicionar uma etapa extra colocando-os em uma bashvariável.
Kusalananda

Respostas:


18

Isso pode ser resolvido através da sintaxe pura do shell. Requer uma variável temporária devido aos parênteses (colchetes), embora:

#!/bin/bash

LATLNG="(53.3096,-6.28396)"

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

Como alternativa, você pode fazê-lo de uma só vez, brincando IFSe usando o readbuiltin:

#!/bin/bash

LATLNG="(53.3096,-6.28396)"

IFS='( ,)' read _ LAT LNG _ <<<"$LATLNG"

O primeiro exemplo funcionará apenas no bash, não no shell POSIX.
gelraen

1
@gelraen daí o#!/bin/bash
SiegeX

Veja mais expansões aqui: gnu.org/software/bash/manual/…
Ricardo Stuven

22

A resposta do SiegeX é melhor para este caso em particular, mas você também deve saber como passar texto arbitrário sed.

sedespera nomes de arquivos como seu segundo, terceiro, etc. parâmetros e, se não encontrar nenhum nome de arquivo, ele lê sua entrada padrão. Portanto, se você tiver um texto que deseja processar que não esteja em um arquivo, precisará canalizá-lo sed. A maneira mais direta é esta:

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

Portanto, seu exemplo se tornaria:

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

Métodos alternativos (melhores, porém mais obscuros)

Se você acha que há alguma chance de $LATLNGcomeçar com um traço, ou se você quer ser pedante, useprintf vez de echo:

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

Ou um "documento aqui", mas isso pode ser um pouco estranho com a construção que você está usando:

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

Ou, se você estiver usando bashe não estiver preocupado com a portabilidade, poderá usar uma "string aqui":

sed 's/foo/bar/g' <<< "$LATLNG"

3

Aqui está uma solução que funcionará em qualquer 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"

Aqui está outra solução igualmente portátil que analisa a sintaxe específica usada.

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

-1
LATLNG="(53.3096,-6.28396)"
set ${LATLNG//[(,)]/ }
LAT=$1
LON=$2

Você provavelmente deveria fazer set -- ...Há uma chance muito boa de o primeiro personagem ser -.
precisa
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.