Bash-Variable mit sed verarbeiten

16

Die Bash-Variable LATLNG enthält einen Breiten- und Längengrad in eckigen Klammern

(53.3096,-6.28396)

Ich möchte diese in eine Variable mit dem Namen LAT und LON zerlegen, was ich mit sed so versuche

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

Ich erhalte jedoch den folgenden Fehler:

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

conorgriffin
quelle
1
Lernen Sie eine Skriptsprache wie Python, Ruby oder sogar PERL, damit Sie die Shell nicht zwingen müssen, alles für Sie zu tun. Sie können sogar Javascript (Rhino) auf einem UNIX-System ausführen, und fast jeder muss etwas Javascript kennen.
Michael Dillon
Woher kommen diese Werte? Es wäre effizienter, die Breiten- und Längengrade aus der ursprünglichen Quelle zu analysieren, als einen zusätzlichen Schritt hinzuzufügen, indem Sie sie in eine bashVariable einfügen.
Kusalananda

Antworten:

18

Dies kann durch reine Shell-Syntax gelöst werden. Aufgrund der Klammern (Klammern) ist jedoch eine temporäre Variable erforderlich:

#!/bin/bash

LATLNG="(53.3096,-6.28396)"

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

Alternativ können Sie es in einem Zug tun, indem Sie mit IFSdem readeingebauten Code spielen und ihn verwenden :

#!/bin/bash

LATLNG="(53.3096,-6.28396)"

IFS='( ,)' read _ LAT LNG _ <<<"$LATLNG"
SiegeX
quelle
Das erste Beispiel funktioniert nur in Bash, nicht in der POSIX-Shell.
Gelraen
1
@gelraen daher die#!/bin/bash
SiegeX
Weitere Erweiterungen finden Sie hier: gnu.org/software/bash/manual/…
Ricardo Stuven
22

Die Antwort von SiegeX ist in diesem speziellen Fall besser, Sie sollten jedoch auch wissen, wie Sie beliebigen Text übergeben sed.

sederwartet Dateinamen als zweiten, dritten usw. Parameter, und wenn keine Dateinamen gefunden werden, wird von der Standardeingabe gelesen. Wenn Sie also Text haben, den Sie verarbeiten möchten, der nicht in einer Datei enthalten ist, müssen Sie ihn weiterleiten sed. Der einfachste Weg ist dieser:

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

So würde Ihr Beispiel werden:

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

Alternative (bessere, aber obskurere) Methoden

Wenn Sie glauben, dass eine Chance besteht, $LATLNGdie mit einem Bindestrich beginnen könnte, oder wenn Sie pedantisch sein möchten, sollten Sie printfanstelle von Folgendes verwenden echo:

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

Oder ein "hier Dokument", aber das kann mit dem Konstrukt, das Sie verwenden, etwas umständlich sein:

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

Wenn Sie bashPortabilität nicht befürchten, können Sie auch eine "Here-Zeichenfolge" verwenden:

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

Hier ist eine Lösung, die in jeder POSIX-Shell funktioniert:

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"

Hier ist eine weitere gleichermaßen portable Lösung, die die verwendete spezifische Syntax analysiert.

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 - hör auf böse zu sein'
quelle
-1
LATLNG="(53.3096,-6.28396)"
set ${LATLNG//[(,)]/ }
LAT=$1
LON=$2
2nil
quelle
Das solltest du wahrscheinlich tun. set -- ...Es besteht eine sehr gute Chance, dass der erste Charakter a ist -.
mikeserv