1

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."
  • have you try: sed 's/.....' "$drill_file_temp" – Romeo Ninov Feb 6 '15 at 18:03
  • "it expands just fine outside the shell"?? – Hauke Laging Feb 6 '15 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 '15 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 '15 at 20:57
  • Doesn't work... – 71GA Feb 6 '15 at 21:11
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"

  • Putting eval in front does not work – 71GA Feb 6 '15 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 – Hauke Laging Feb 6 '15 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 '15 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
  • It's even worse: It doesn't work that way... – Hauke Laging Feb 6 '15 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.