2016-12-18 2 views
1

В моем скрипте bash я безуспешно пытаюсь получить адрес файла, который не завернут в двойные кавычки, по какой-то причине для того, чтобы быть обернутым в двойные кавычки, чтобы мой скрипт и прочитал адрес как один токен и введите этот адрес в адреса элементов массива. то есть я хочуКак перенести неуказанный адрес в файл с помощью bash?

42 Example Lane Bash City Bashland 

стать

"42 Example Lane Bash City Bashland" 

так что я могу назначить его ARRAY [4] в моем сценарии. Любые идеи о том, как получить двойные кавычки, обернутые вокруг адреса, которые не имеют двойных кавычек? Его в .txt структуре строки файла следующим образом:

FirstName LastName dd/mm/yyyy Address 

Как обернуть двойные кавычки вокруг адресов, которые не имеют их? Я попробовал sed, но, похоже, я попал в блокпост, пытаясь получить неуказанные адреса, указанные для обработки в виде единственного токена в скрипте.

+1

Похоже, вы пишете сценарий оболочки для управления текстом. Если так, не делайте этого, поскольку это не то, для чего предназначена оболочка. Оболочка предназначена для управления файлами/процессами и последовательными вызовами инструментов. Стандартный универсальный UNIX-инструмент для управления текстом - awk. Итак, если вы манипулируете текстом с помощью оболочки UNIX, часть оболочки должна быть просто вызовом awk. Получите книгу «Эффективное программирование Awk», 4-е издание, Арнольд Роббинс, чтобы узнать awk и посмотреть http://unix.stackexchange.com/questions/169716/why-is-using-a-shell-loop-to-process-text- считается плохой практикой для получения дополнительной информации о том, почему не оболочка. –

+0

Привет, спасибо за отзыв. Я в основном читаю нечистые данные из входного файла и распределяю результаты в созданной структуре выходных файлов (по сценарию) в соответствии с выходными спецификациями. Проблема с манипуляцией, которую я имею здесь, является проверкой адреса, команда чтения очень удобна, но если адрес (множественный атрибут слова) не заключен в кавычки и, таким образом, рассматривается как один токен, адреса первого слова вытягиваются из адреса, который не заключен в кавычки. Это моя текущая проблема на этом этапе разработки. Приветствую вас за подсказку на awk bro !! .. Я изучу !! .. –

+1

Спасибо всем за ваши материалы, я узнал о нагрузках от решений и о том, как они применимы к моему частично построенному скрипту. Я собираюсь пойти с регулярным выражением, поскольку он наиболее точно соответствует потоку моего сценария, как предлагал SLePort! –

ответ

1

Попробуйте это:

$ sed 's/\(.*[0-9]\{2\}\/[0-9]\{2\}\/[0-9]\{4\} \)\([^"]\)\(.*\)\([^"]\)$/\1"\2\3\4"/' <<< "John Doe 04/12/1960 42 Example Lane, Bash City, Bashland" 
John Doe 04/12/1960 "42 Example Lane, Bash City, Bashland" 

Все символы до и после даты съемки. Используя обратные ссылки, захваченные группы выводятся с окружающими ".

Для редактирования файла вместо, добавьте -i флаг СЭД:

sed 's/\(.*[0-9]\{2\}\/[0-9]\{2\}\/[0-9]\{4\} \)\([^"]\)\(.*\)\([^"]\)$/\1"\2\3\4"/' file.txt 

Edit:

Тот же результат и, возможно, немного более удобным для чтения с расширенными регулярными выражениями:

sed -E 's/(.*[0-9]{2}\/[0-9]{2}\/[0-9]{4})([^"])(.*)([^"])$/\1"\2\3\4"/' <<< 'John Doe 04/12/1960 42 Example Lane, Bash City, Bashland' 
+0

Спасибо, что ... это регулярное выражение работало для меня, переписывая дополнительный цикл в мой скрипт, чтобы очистить распределенные выходы. –

0

FirstName LastName dd/mm/yyyy Address? Как насчет двойного первого или двойного LastNames? Luckelly ypu интересуется только частью после "/yyyy ". Когда вы новичок, начните с небольшими шагами, которые вы понимаете:

# Remove first part of string. In `sed` you can use `#`when `/` is part of your string. 
echo "Mr John F Someone 11/04/2008 44 street somewhere" | sed 's#.*/.... ##' 
# Put string in quotes 
echo "Mr John F Someone 11/04/2008 44 street somewhere" | sed 's/.*/"&"/' 
# Put string in quotes differently (for later study) 
printf '"%s"\n' "$(echo "Mr John F Someone 11/04/2008 44 street somewhere")" 
# Combine two sed commands (after a pipe you can enter a newline) 
echo "Mr John F Someone 11/04/2008 44 street somewhere" | 
    sed -e 's#.*/.... ##' -e 's/.*/"&"/' 
# Or 
echo "Mr John F Someone 11/04/2008 44 street somewhere" | 
    sed 's#.*/.... ##;s#.*#"&"#' 
# Or 
echo "Mr John F Someone 11/04/2008 44 street somewhere" | 
    sed -e 's#.*/.... \(.*\)#"\1"#' 
1

В Баше, вы вообще не нужны (или хотите) котировки в ваших данных. Котировки идут около данных, а не в нем. Вы почти всегда должны иметь двойные кавычки вокруг переменных ссылок, но почти никогда не сохраняете какие-либо кавычки как часть данных в переменных. Но детали будут зависеть именно от того, что вы делаете. Вот простой пример:

read firstName lastName date address <file.txt 
# Note that if there are more space-separated "words" in the line than variables, 
# `read` lumps everything into the last variable (i.e. address) 
userArray=("$firstName" "$lastName" "$date" "$address") 
# Double-quotes keep $address from being split into multiple array entries 
echo "${userArray[0]} ${userArray[1]}'s address is:" 
# Note that one set of double-quotes is enough to protect the whole string, 
# even though there are multiple variable references in it. 
echo " ${userArray[3]}" 

Если вам нужны котировки на выходе, добавить их при выводе данных:

echo "Address='$address'" # Single-quotes around data 
echo "Address=\"$address\"" # Double-quotes must be escaped inside other double-quotes 

Если вы зацикливание над файлом, вы бы использовать что-то вроде этого :

while read firstName lastName date address; do 
    # do stuff with the data 
done <file.txt 

BTW, задействуя разные виды данных (имя, дата и т.д.) в массивах немного странно; обычно вы используете массивы для хранения списка значений одного и того же типа. Но опять же, это зависит от конкретной ситуации.

+0

Cheers Gorden .. Я вижу, откуда вы. Проблема, которую я пытаюсь получить, проверяет адрес, где я читаю файл, вводимый по строке, затем объявляю и вводим его в массив. Массив не будет читать адрес полностью в виде единственного токена, если только он не получит двойные кавычки, и я хочу, чтобы предварительная обработка валидации строки считывалась в массив (элементы). –

+1

@JohnMulhall: Большинство методов установки массива в bash соответствуют правилу, которое я дал: они уважают кавычки вокруг данных, но не в нем. Например, если у вас есть 'raw_line = 'Joe Smith 11/22/33" 42 Пример Lane Bash City Bashland "'', тогда do 'declare -a foo = ($ raw_line)', вы получите массив у которого есть элементы «Joe '' Smith» '11/22/33 '' '42' 'Пример' 'Lane' 'Bash' 'City' и 'Bashland' '- поскольку двойные кавычки были * в * переменная, а не * вокруг * она, они просто рассматриваются как часть данных, а не как синтаксически значимые. –

+0

Получил это ... спасибо Gordon .... записи файлов работают без кавычек в отдельные файлы папок, записывающих индивидуальную информацию .... –

1

Если производительность не является первостепенной, собственным readBash встроенным предлагает удобное решение:

пример использует вместо ввода текста файл here-document; для использования файла, замените <<'EOF' и все остальные строки < your-file.txt).

while read -r first last date addr; do 
    [[ $addr == \"*\" ]] || addr="\"$addr\"" 
    echo "first: [$first], last: [$last], date: [$date], addr: [$addr]" 
done <<'EOF' 
First1 Last1 dd/mm/yyyy Address one unquoted 
First2 Last2 dd/mm/yyyy "Address two double-quoted" 
EOF 

Это дает:

first: [First1], last: [Last1], date: [dd/mm/yyyy], addr: ["Address one unquoted"] 
first: [First2], last: [Last2], date: [dd/mm/yyyy], addr: ["Address two double-quoted"] 

Это решение:

  • использует тот факт, что read читает остаток строки в последней переменной, указанной, если в строке ввода меньше переменных, чем полей.

  • [[ $addr == \"*\" ]] испытания, если значение, считанное в $addr уже есть " -enclosed (обратите внимание на необходимость \ экранирующего в " символы. С тем, чтобы рассматривать их как литералов) и, если нет (||), заменяет значение $addr с собой, заключенное в ".


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

while read -r first last date addr; do 
    [[ $addr =~ \"(.*)\" ]] && addr="${BASH_REMATCH[1]}" 
    echo "first: [$first], last: [$first], date: [$first], addr: [$addr]" 
done <<'EOF' 
First1 Last1 dd/mm/yyyy Address one unquoted 
First2 Last2 dd/mm/yyyy "Address two double-quoted" 
EOF 

Это дает:

first: [First1], last: [First1], date: [First1], addr: [Address one unquoted] 
first: [First2], last: [First2], date: [First2], addr: [Address two double-quoted] 

Как вы можете видеть, " символы. окружение адреса на второй строке ввода было удалено из значения, хранящегося в $addr.

Это решение:

  • использует =~, Bash's regex-matching operator для соответствия адреса, заключенных в буквальных двойных кавычек (\"(.*)\")

  • и, если это так (&&), переопределяет $addr в строку между заключенные двойные кавычки, через значение, которое заключено в скобки подвыражения (группа захвата, (.*)), захвачено (${BASH_REMATCH[1]}).