0

I'm trying to replace the LIBNAME statements in a SAS program. An example of a line that I would want to modify is:

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

I want to leave the somelib string intact and replace only the '/random/path/reference/' with a variable that I've defined, e.g. /some/fake/path/ (but enclosed in single quotes)

When trying to do the sed substitution, I'm getting an error advising that,

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

The code that cannot be parsed is basically:

test_path=/some/fake/path/

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

I'm pretty much at my wit's end at this point.

1
  • 1
    Please, simplify your question to only line which should be modified, sed substitution and desired output. For example, echo 'your line which you want to modify' | sed 'do something' and Output should be: some desired output
    – Gryu
    Jun 26 '20 at 21:28
1

From your original script posted (now edited out):

Why four different regex ?? (well three, reg3 seems to be identical to the sed regex reported in your error line):

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`

Problem description

Your whole problem could be reduced to this code:

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'

Which will print LIBNAME somelib "/some/fake/path/".

If the regex doesn't match, nothing gets printed.

Solution script

That leads to write this script:

#!/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

A simpler solution, but still ...

Recommended script

But, knowing that a shell is not the best way to edit a file.
Having already reduced the whole script to a sed regex.

We should reduce the script even more to the simpler:

#!/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

code issues
There are some issues in your code.

  1. You claim to need to modify LIBNAME somelib '/random/path/reference/';, with single quotes. But your code (regex) is trying to match double quotes: LIBNAME somelib "/random/path/reference/"; Which is it?
  2. Quote your variables, echo $line is wrong. Use: echo "$line".
  3. Modify the value of $line and print it only once.
  4. Since there will be only one echo "$line" we may as well do it for the whole loop.
  5. Use ; to place the do's.
  6. Why do you have a dot in your first regex? To match a dot you need \.
  7. You can not use a s/// if the text is going to contain /. Use s@@@, for example.
  8. As you are using a flag of I (s///I) you must use the GNU sed, are you?
  9. In sed BRE there is no alternation |. Only in GNU sed you could use \|.
  10. Please reduce the number of regexes as much as possible, each one is a potential source of misinterpretations.
  11. You can set a new variable to the modified value of line if it match the regex. If the variable is empty, the regex didn't match.
3
  • Isaac, thank you so much for all of the information. None of the code you posted produces the desired output for me, unfortunately. The reason for the different regexs is that I don't want to alter a line that has libname [some text] oracle path, but only lines with a libname statement that are not references to an oracle path.
    – nraslan
    Jun 29 '20 at 18:18
  • @nraslan Hmmm "produces the desired output for me" isn't very specific. If you want to improve please supply more information of what you ran, what output you've got, and what output you would like to get. Also: What version of sed are you running: (sed --version maybe?) ?
    – ImHere
    Jun 29 '20 at 23:09
  • None of the commands worked in the shell I'd been using (Version M-11/16/88f), but when I switched to a different shell (which has GNU sed 4.2.2), what you posted works. Thank you!!
    – nraslan
    Jun 30 '20 at 14:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.