Замена Sed переменной Unix KSH в кавычках

Я пытаюсь заменить операторы LIBNAME в программе SAS. Пример строки, которую я хотел бы изменить:

LIBNAME somelib '/random/path/reference/';

Я хочу оставить строку somelibнетронутой и заменить только '/random/path/reference/'на переменная, которую я определил, например /some/fake/path/(но заключено в одинарные кавычки)

При попытке выполнить замену sedя получаю сообщение об ошибке

sed: 0602-404 Function s/\(libname[[:space:]]\{1,\}[[:alnum:]]\{1,\}[[:space:]]\{1,\}\)\("([^"]|\\")*"\)/\2\"/some/fake/path/"/ cannot be parsed.

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

test_path=/some/fake/path/

sed 's/\(libname[[:space:]]\{1,\}[[:alnum:]]\{1,\}[[:space:]]\{1,\}\)\("([^"]|\\")*"\)/\2\"'$test_path'"/I'

В этот момент я практически потерял рассудок.

0
27.06.2020, 07:34
1 ответ

Из вашего исходного опубликованного сценария (теперь отредактировано):

Почему четыре разных регулярных выражения ?? (хорошо три, reg3 кажется идентичным регулярному выражению sed, указанному в вашей строке ошибки):

reg1='libname[[:space:]]\{1,\}[[:alnum:]]\{1,\}\.[[:alnum:]]\{1,\}[[:space:]]\{1,\}oracle path'
reg2='libname[[:space:]]\{1,\}'
reg3='\(libname[[:space:]]\{1,\}[[:alnum:]]\{1,\}[[:space:]]\{1,\}\)\("([^"]|\\")*"\)'
sed1='s/\(libname[[:space:]]\{1,\}[[:alnum:]]\{1,\}[[:space:]]\{1,\}\)\("([^"]|\\")*"\)/\2"/some/fake/path/"/I`

Описание проблемы

Всю вашу проблему можно свести к этому коду:

sourcepath='/random/path/reference/'
test_path='/some/fake/path/'

echo "LIBNAME somelib \"$sourcepath\"" | 
    sed -n 's@\(LIBNAME[[:space:]]\{1,\}[[:alnum:]]\{1,\}[[:space:]]\{1,\}\)\("\(\([^"]\|\\"\)*\)"\)@\1"'"$test_path"'"@p'

Который напечатает LIBNAME somelib "/some/fake/path/".

Если регулярное выражение не совпадает, ничего не печатается.

Сценарий решения

Это приводит к написанию этого скрипта:

#!/bin/ksh -
test_path=/some/fake/path/

reg1='libname[[:space:]]\{1,\}[[:alnum:]]\{1,\}.[[:alnum:]]\{1,\}[[:space:]]\{1,\}oracle path'
reg2='\(LIBNAME[[:space:]]\{1,\}[[:alnum:]]\{1,\}[[:space:]]\{1,\}\)\("\(\([^"]\|\\"\)*\)"\)'
:>./edited.sas

while IFS=$' \t\n' read -r line; do
    newline=$(echo "$line" | sed -n 's@'"$reg2"'@\1"'"$test_path"'"@p')
    if [ -n "$newline" ]; then
        line=$newline
    fi
    echo "$line" 
done <./original.sas  >>./edited.sas

Более простое решение, но все же...

Рекомендуемый скрипт

Но, зная, что оболочка - не лучший способ редактирования файла.
Уже сократив весь скрипт до регулярного выражения sed.

Мы должны еще больше упростить сценарий:

#!/bin/ksh

test_path=/some/fake/path/

reg1='\(LIBNAME[[:space:]]\{1,\}[[:alnum:]]\{1,\}[[:space:]]\{1,\}\)\("\(\([^"]\|\\"\)*\)"\)'

sed 's@'"$reg1"'@\1"'"$test_path"'"@'./original.sas  >./edited.sas

проблемы с кодом
В вашем коде есть некоторые проблемы.

  1. Вы утверждаете, что вам нужно изменить LIBNAME somelib '/random/path/reference/';с одинарными кавычками. Но ваш код (регулярное выражение )пытается сопоставить двойные кавычки :LIBNAME somelib "/random/path/reference/";. Что это?
  2. Приведите свои переменные, echo $lineневерно. Используйте:echo "$line".
  3. Измените значение $lineи распечатайте его только один раз.
  4. Так как будет только один echo "$line", мы можем сделать это для всего цикла.
  5. Используйте ;для размещения do.
  6. Почему в первом регулярном выражении стоит точка? Чтобы сопоставить точку, вам нужно\.
  7. Вы можете не использовать s///, если текст будет содержать /. Используйте, например, s@@@.
  8. Поскольку вы используете флаг I(s///I), вы должны использовать GNU sed, не так ли?
  9. В sed BRE нет чередования |. Только в GNU sed вы можете использовать \|.
  10. Пожалуйста, максимально сократите количество регулярных выражений, каждое из которых является потенциальным источником неверного толкования.
  11. Вы можете установить новую переменную в измененное значение строки, если оно соответствует регулярному выражению. Если переменная пуста, регулярное выражение не соответствует.
1
18.03.2021, 23:23

Теги

Похожие вопросы