Если производительность не является первостепенной, собственным read
Bash встроенным предлагает удобное решение:
пример использует вместо ввода текста файл 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]}
).
Похоже, вы пишете сценарий оболочки для управления текстом. Если так, не делайте этого, поскольку это не то, для чего предназначена оболочка. Оболочка предназначена для управления файлами/процессами и последовательными вызовами инструментов. Стандартный универсальный UNIX-инструмент для управления текстом - awk. Итак, если вы манипулируете текстом с помощью оболочки UNIX, часть оболочки должна быть просто вызовом awk. Получите книгу «Эффективное программирование Awk», 4-е издание, Арнольд Роббинс, чтобы узнать awk и посмотреть http://unix.stackexchange.com/questions/169716/why-is-using-a-shell-loop-to-process-text- считается плохой практикой для получения дополнительной информации о том, почему не оболочка. –
Привет, спасибо за отзыв. Я в основном читаю нечистые данные из входного файла и распределяю результаты в созданной структуре выходных файлов (по сценарию) в соответствии с выходными спецификациями. Проблема с манипуляцией, которую я имею здесь, является проверкой адреса, команда чтения очень удобна, но если адрес (множественный атрибут слова) не заключен в кавычки и, таким образом, рассматривается как один токен, адреса первого слова вытягиваются из адреса, который не заключен в кавычки. Это моя текущая проблема на этом этапе разработки. Приветствую вас за подсказку на awk bro !! .. Я изучу !! .. –
Спасибо всем за ваши материалы, я узнал о нагрузках от решений и о том, как они применимы к моему частично построенному скрипту. Я собираюсь пойти с регулярным выражением, поскольку он наиболее точно соответствует потоку моего сценария, как предлагал SLePort! –