Подтвердить что ты не робот

Разделить строку (хранящуюся в переменной) на несколько слов, используя пробелы, но не пробелы в двойных кавычках

Я пытаюсь написать для меня сложную script, где моя цель - сделать следующее. У меня есть строка, которая выглядит так:

2012 2013 "multiple words"

Моя цель - поместить каждый из них в массив, разделенный пробелами, но только для совпадений с одним словом, а не с двойными кавычками. Это следует рассматривать как одно слово. Поэтому я решил сделать это в два этапа. Сначала сопоставьте те слова, которые являются кратными, удалите их из строки, а затем в другой итерации, разделенной пробелом.
К сожалению, я не могу найти помощь, как echo только совпадение. Пока у меня есть это:

array=$(echo $tags | sed -nE 's/"(.+)"/\1/p')

Но это приведет к (на OS X):

2012 2013 multiple words

Ожидаемый результат:

array[1]="2012"
array[2]="2013"
array[3]="multiple words"

Как мне решить эту проблему?

Спасибо.

4b9b3361

Ответ 1

eval является злом, но это может быть один из тех случаев, когда он удобен

str='2012 2013 "multiple words"'
eval x=($str)
echo ${x[2]}
multiple words

Или с более поздними версиями bash (проверено в 4.3)

s='2012 2013 "multiple words"'
declare -a 'a=('"$s"')'
printf "%s\n" "${a[@]}"
2012
2013
multiple words

Ответ 2

$ grep -Eo '"[^"]*"|[^" ]*' <<< '2012 2013 "multiple words"'
2012
2013
"multiple words"

То есть напечатайте только строки, соответствующие либо

  • цитата, за которой следует любое число (даже ноль) не кавычек, за которым следует цитата или
  • ряд символов, не содержащих цитату или пробел.

Конечно, это не обрабатывает сложные случаи, такие как кавычки, охватывающие несколько строк или экранированные кавычки (используя либо двойные кавычки, как SQL, либо обратную косую черту, подобно оболочке).

Ответ 3

Вы можете напрямую:

arr=(2012 2013 "multiple words")

echo ${#arr[@]} # gives 3
echo ${arr[2]} # gives "multiple words"

РЕДАКТИРОВАТЬ: Не уверен, что он помогает OP, но после этого также будет работатьL

str='2012 2013 "multiple\ words"'
read -a arr <<< $str
echo ${#arr[@]} # gives 3
echo ${arr[2]} # gives "multiple words"

Ответ 4

Ниже приведен результат, который вы хотите:

tags='2012 2013 "multiple words"'
IFS=$'\n'; array=($(echo $tags | egrep -o '"[^"]*"|\S+'))

приведет к ZSH:

echo ${array[1]} # 2012
echo ${array[2]} # 2013
echo ${array[3]} # "multiple words"

приведет к BASH:

echo ${array[0]} # 2012
echo ${array[1]} # 2013
echo ${array[2]} # "multiple words"

работает в OSX.

Ответ 5

Вот небольшой Python script для синтаксического разбора пространства csv с соблюдением цитируемых полей:

$ python -c '
import csv, fileinput
for line in csv.reader(fileinput.input(), delimiter=" "):
   for word in line:
      print word
' test.csv
2012
2013
multiple words

Так как это использует модуль fileinput, он также работает в конвейере (или в строке в переменной):

$ str='2012 2013 "multiple words"'
$ echo $str | python -c '
import csv, fileinput
for line in csv.reader(fileinput.input(), delimiter=" "):
   for word in line:
      print word
' 
2012
2013
multiple words