Memproses variabel bash dengan sed

16

variabel bash LATLNG berisi nilai garis lintang & bujur dalam tanda kurung seperti itu

(53.3096,-6.28396)

Saya ingin menguraikan ini menjadi variabel yang disebut LAT dan LON yang saya coba lakukan melalui sed seperti itu

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

Namun, saya mendapatkan kesalahan berikut:

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

Conorgriffin
sumber
1
Pelajari bahasa scripting seperti Python, Ruby, bahkan mungkin PERL, sehingga Anda tidak perlu memaksa shell untuk melakukan segalanya untuk Anda. Anda bahkan bisa mendapatkan Javascript (Badak) untuk dijalankan pada sistem UNIX dan hampir semua orang perlu mengetahui beberapa Javascript.
Michael Dillon
Dari mana nilai-nilai ini berasal? Akan lebih efisien untuk mem-parsing nilai lintang dan bujur dari sumber asli daripada menambahkan langkah ekstra dengan meletakkannya dalam bashvariabel.
Kusalananda

Jawaban:

18

Ini dapat diselesaikan melalui sintaksis shell murni. Itu memang memerlukan variabel temp karena kurung (kurung):

#!/bin/bash

LATLNG="(53.3096,-6.28396)"

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

Sebagai alternatif, Anda dapat melakukannya dalam sekali jalan dengan bermain dengan IFSdan menggunakan readbuiltin:

#!/bin/bash

LATLNG="(53.3096,-6.28396)"

IFS='( ,)' read _ LAT LNG _ <<<"$LATLNG"
SiegeX
sumber
Contoh pertama hanya akan bekerja di bash, bukan di shell POSIX.
gelraen
1
@gelraen karenanya#!/bin/bash
SiegeX
Lihat ekspansi lainnya di sini: gnu.org/software/bash/manual/…
Ricardo Stuven
22

Jawaban SiegeX lebih baik untuk kasus khusus ini, tetapi Anda juga harus tahu cara menyampaikan teks arbitrer sed.

sedmengharapkan nama file sebagai parameter kedua, ketiga, dll., dan jika tidak menemukan nama file, itu dibaca dari input standarnya. Jadi jika Anda memiliki teks yang ingin Anda proses yang tidak ada dalam file, Anda harus mem-pipe-nya sed. Cara yang paling mudah adalah:

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

Jadi contoh Anda akan menjadi:

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

Metode Alternatif (lebih baik tetapi lebih jelas)

Jika Anda berpikir ada peluang yang $LATLNGbisa dimulai dengan tanda hubung, atau jika Anda ingin menjadi bertele-tele, Anda harus menggunakan printfsebagai ganti echo:

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

Atau "dokumen di sini", tetapi itu bisa sedikit canggung dengan konstruk yang Anda gunakan:

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

Atau jika Anda menggunakan bashdan tidak khawatir tentang portabilitas, Anda dapat menggunakan "string di sini":

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

Inilah solusi yang akan bekerja di semua 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"

Inilah solusi lain yang sama-sama portabel yang mem-parsing sintaks khusus yang digunakan.

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- berhenti menjadi jahat'
sumber
-1
LATLNG="(53.3096,-6.28396)"
set ${LATLNG//[(,)]/ }
LAT=$1
LON=$2
2nil
sumber
Anda mungkin harus melakukannya. set -- ...Ada kesempatan yang sangat baik karakter pertama adalah a -.
mikeserv