问题描述

问题描述

我正在尝试替换 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

代码问题
您的代码中存在一些问题。

  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///如果文本要包含 则使用 a /s@@@例如,使用。
  8. I当您使用( )标志时,s///I您必须使用 GNU sed,是吗?
  9. 在 sed BRE 中没有交替|。只有在 GNU sed 中你才能使用\|.
  10. 请尽可能减少正则表达式的数量,每个正则表达式都是潜在的误解来源。
  11. 如果新变量与正则表达式匹配,则可以将新变量设置为 line 的修改值。如果变量为空,则正则表达式不匹配。

相关内容