我正在尝试替换 SAS 程序中的 LIBNAME 语句。我想要修改的行的一个示例是:
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'
我现在已经无计可施了。
答案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
一个更简单的解决方案,但仍然......
推荐脚本
但是,要知道 shell 并不是编辑文件的最佳方法。
已经将整个脚本简化为 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///
如果文本要包含 则使用 a/
。s@@@
例如,使用。 I
当您使用( )标志时,s///I
您必须使用 GNU sed,是吗?- 在 sed BRE 中没有交替
|
。只有在 GNU sed 中你才能使用\|
. - 请尽可能减少正则表达式的数量,每个正则表达式都是潜在的误解来源。
- 如果新变量与正则表达式匹配,则可以将新变量设置为 line 的修改值。如果变量为空,则正则表达式不匹配。