Я пытаюсь заменить операторы 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'
В этот момент я практически потерял рассудок.
Из вашего исходного опубликованного сценария (теперь отредактировано):
Почему четыре разных регулярных выражения ?? (хорошо три, 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
проблемы с кодом
В вашем коде есть некоторые проблемы.
LIBNAME somelib '/random/path/reference/';
с одинарными кавычками. Но ваш код (регулярное выражение )пытается сопоставить двойные кавычки :LIBNAME somelib "/random/path/reference/";
. Что это? echo $line
неверно. Используйте:echo "$line"
. $line
и распечатайте его только один раз. echo "$line"
, мы можем сделать это для всего цикла. ;
для размещения do
. \.
s///
, если текст будет содержать /
. Используйте, например, s@@@
. I
(s///I
), вы должны использовать GNU sed, не так ли? |
. Только в GNU sed вы можете использовать \|
.