2

I have this script, which will prompt for the relative or absolute path to the file and then swap whitespaces ' ' with '\ ' which works in Linux console. Substitution is done using the first sed command. After substitution I echo the path just for check and it is correct.

Then comes the second sed command which has to deal with the file for which I wrote the absolute path. Well it won't work... It looks like In the second command $drill_file isn't expanding. The weirdest thing is that it expands just fine outside the script... WOOT!?

#!/bin/bash

echo "Give relative or absolute path to the \"drill.TXT\" file:"

read drill_file_temp
drill_file=$(echo $drill_file_temp | sed -r 's/\s/\\ /g')
echo $drill_file

sed 's/\(^X[[:digit:]]*\)[[:digit:]]\(Y[[:digit:]]*\)[[:digit:]]/\1\2/' $drill_file

echo "Conversion finished."
5
  • have you try: sed 's/.....' "$drill_file_temp" Feb 6, 2015 at 18:03
  • "it expands just fine outside the shell"?? Feb 6, 2015 at 18:23
  • @Hauke I meant script - I fixed the mistake. Romeo. No I haven't tried yet because usualy 'echo "$variable"' returns same as 'echo $variable'
    – 71GA
    Feb 6, 2015 at 20:52
  • @Romeo. If I only add " ", then I get an error saying: sed: can't read /home/ziga/Dropbox/workspace/programi/eagle/projects/ISKRA/SLON\ -\ razsiritvena\ ploscica/v2.0/gerber/drill.TXT: No such file or directory but If I execute sed manualy it works - I do it like this: sed 's/\(^X[[:digit:]]*\)[[:digit:]]\(Y[[:digit:]]*\)[[:digit:]]/\1\2/' /home/ziga/Dropbox/workspace/programi/eagle/projects/ISKRA/SLON\ -\ razsiritvena\ ploscica/v2.0/gerber/drill.TXT
    – 71GA
    Feb 6, 2015 at 20:57
  • Doesn't work...
    – 71GA
    Feb 6, 2015 at 21:11

3 Answers 3

2

You put quoting chars into a string. The problem is that quoting chars are not parsed after parameter expansion. In order to get the desired effect you would need

eval sed ... $drill_file

You can use set -x to see how the shell sees the command line:

> text=a\\\ \\\ \\\ b
> echo $text
a\ \ \ b
> set -x
> : $text
+ : 'a\' '\' '\' b

I.e. the shell does not see one argument but four.

As aleady said by the others: You must quote $drill_file / $drill_file_temp: "$drill_file"

3
  • Putting eval in front does not work
    – 71GA
    Feb 6, 2015 at 21:08
  • @71GA It doesn't work if you forget the additional quoting layer you need for the sed command part. You can easily check with my simple example code: eval : $text Feb 6, 2015 at 21:17
  • OK thank you I had to use eval and " " on the original path and not the edited. I mean who should know that I am forbidden to edit the path - in Linux whitespaces should be written as "\ " afterall... Not intuitive at all...
    – 71GA
    Feb 6, 2015 at 22:16
2

You don't need to do the first sed if you quote your variables:

read -p "Give relative or absolute path to the \"drill.TXT\" file: " drill_file
if [[ -f "$drill_file" ]]; then
    sed 's/\(^X[[:digit:]]*\)[[:digit:]]\(Y[[:digit:]]*\)[[:digit:]]/\1\2/' "$drill_file"
    echo "Conversion finished."
else
    echo "no such file: '$drill_file'"
fi
1
  • It's even worse: It doesn't work that way... Feb 6, 2015 at 18:16
0

kernel doesn't understand \ (backslash)
If drill_file is 'file\ with\ space', sed is executed as
sed 's/\(^X[[:digit:]]*\)[[:digit:]]\(Y[[:digit:]]*\)[[:digit:]]/\1\2/' file\ with\ space.
First the shell clones itself and calls one the of execl family of functions passing args with argv[0]=sed, argv[1]=s/(^X[[:digit:]])[[:digit:]](Y[[:digit:]])[[:digit:]]/\1\2/, argv[2]=file\ , argv[3]=with\ and argv[4]=space. execl replaces shell with sed. When sed starts running, it calls open("file\ ",O_RDONLY)and does the same for 'with\ ' and 'space'. Kernel passes the request to relevent fs. Fs returns ENOENT meaning no such entry in the fs. That's true because really there are no such files. sed receives the error and displays error message.

if the $drill_file was quoted, sed gets the file name as 'file\ with\ space' and fails to open this time too.

eval sed 's/\(^X[[:digit:]]*\)[[:digit:]]\(Y[[:digit:]]*\)[[:digit:]]/\1\2/' "$drill_file"
here eval parses its args and builds commands and executes the built command. It's just redundant and convoluted, you break and fix.

\ (backslash) escaping is only applicable when shell is running.sed 's/\(^X[[:digit:]]*\)[[:digit:]]\(Y[[:digit:]]*\)[[:digit:]]/\1\2/' "$drill_file_temp" would have simply succeeded.
This works too.

sed 's/\(^X[[:digit:]]*\)[[:digit:]]\(Y[[:digit:]]*\)[[:digit:]]/\1\2/' \
"$(read -p "Give relative or absolute path to the \"drill.TXT\" file: " \
drill_file_temp;echo $drill_file_temp)"

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.