Обработка bash переменной с помощью sed

16

переменная bash LATLNG содержит значение широты и долготы в скобках, например

(53.3096,-6.28396)

Я хочу разобрать их в переменные с именами LAT и LON, которые я пытаюсь сделать с помощью sed, так

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

Однако я получаю следующую ошибку:

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

conorgriffin
источник
1
Изучите язык сценариев, такой как Python, Ruby, возможно, даже PERL, чтобы вам не пришлось заставлять оболочку делать все за вас. Вы даже можете заставить Javascript (Rhino) работать в системе UNIX, и почти каждый должен знать некоторый Javascript.
Майкл Диллон
Откуда эти ценности? Было бы более эффективно проанализировать значения широты и долготы из исходного источника, чем добавить дополнительный шаг, поместив их в bashпеременную.
Кусалананда

Ответы:

18

Это можно решить с помощью чистого синтаксиса оболочки. Требуется переменная temp из-за круглых скобок:

#!/bin/bash

LATLNG="(53.3096,-6.28396)"

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

Кроме того, вы можете сделать это за один раз, поиграв с IFSпомощью readвстроенного:

#!/bin/bash

LATLNG="(53.3096,-6.28396)"

IFS='( ,)' read _ LAT LNG _ <<<"$LATLNG"
SiegeX
источник
Первый пример будет работать только в bash, а не в оболочке POSIX.
гельраен
1
@gelraen отсюда#!/bin/bash
SiegeX
Смотрите дополнительные дополнения здесь: gnu.org/software/bash/manual/…
Рикардо Стювен,
22

Ответ SiegeX лучше в данном конкретном случае, но вы также должны знать, как передавать произвольный текст sed.

sedожидает имена файлов в качестве второго, третьего и т. д. параметров, и если он не находит никаких имен файлов, он считывает данные из стандартного ввода. Поэтому, если у вас есть текст, который вы хотите обработать, которого нет в файле, вы должны передать его по конвейеру sed. Самый простой способ заключается в следующем:

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

Таким образом, ваш пример станет:

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

Альтернативные (лучше, но более смутные) методы

Если вы думаете, что есть шанс $LATLNGначать с тире, или если вы хотите быть педантичным, вы должны использовать printfвместо echo:

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

Или «здесь документ», но это может быть немного неловко с конструкцией, которую вы используете:

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

Или, если вы используете bashи не беспокоитесь о переносимости, вы можете использовать «здесь строка»:

sed 's/foo/bar/g' <<< "$LATLNG"
Jander
источник
3

Вот решение, которое будет работать в любой оболочке 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"

Вот еще одно не менее переносимое решение, которое анализирует используемый синтаксис.

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
2nil
источник
Вы, вероятно, должны это сделать. set -- ...Очень вероятно, что первый персонаж - это -.
mikeserv