1

I have a script called script.sh:

FILE=$1
sed -i.bak "s|needle|pin|g" $FILE

If I run it like this:

bash ./script.sh /var/www/path/to/file

I get this response:

: No such file or directoryth/to/file

If I run sed by itself, passing in the same path:

sed -i.bak "s|needle|pin|g" "/var/www/path/to/file"

It works fine (even substituting the values correctly).

What am I doing wrong?

Bonus observation: I'm assuming it's telling me the entry path is wrong but it's hard to tell because it says ": No such file or directoryth/to/file", which indicates to me that something else is wrong. Maybe something carriage-return related?

Shoreline
  • 798
  • 1
  • 9
  • 26
  • 2
    You should quote your variables to prevent shell expansion of the value (word splitting, pathname expansion, etc.): `FILE="$1"` and `sed ... "$FILE"`. I'm guessing you haven't given us the real path... – randomir Nov 13 '17 at 17:43
  • 2
    You have non-unix line endings in your script. Clean them up. (eg, run dos2unix) – William Pursell Nov 13 '17 at 18:41
  • This is caused by what is literally **the very first thing** in the "Before Asking About Problematic Code" section of [the `bash` tag info wiki](https://stackoverflow.com/tags/bash/info). – Charles Duffy Nov 13 '17 at 18:44

2 Answers2

6

You should use quotes around your variables to prevent word splitting and filename expansion:

file="$1"
sed -i.bak "s|needle|pin|g" "$file"

(You should also not use all-caps variable names for non-environment variables.)


In bash, each command line (after it has been split in tokens) undergoes a series of shell expansions, in a particular order (emphasis mine):

  • brace expansion;
  • tilde expansion, parameter and variable expansion, arithmetic expansion, process substitution, and command substitution (done in a left-to-right fashion);
  • word splitting; and
  • filename expansion.

So, when you write:

file='filename with spaces'
sed "pat" $file

the $file token will undergo a variable expansion, followed by word splitting, and the command will now look like:

sed pat filename with spaces

meaning, sed received three words for filename, instead of one.

If you use double quotes, the results of parameter expansion, command substitution, and arithmetic expansion that occurred within the double quotes, are not subjected to word splitting and filename expansion. In our example:

file='filename with spaces'
sed "pat" "$file"

is expanded to:

sed "pat" "filename with spaces"

with spaces in filename preserved.

randomir
  • 17,989
  • 1
  • 40
  • 55
1

there must have some unprintable control character in your path string variable, you could print the content of it with declare -p:

FILE=$1
declare -p FILE
J. Anderson
  • 299
  • 1
  • 11
  • It's obviously a very specific control character, the CR (in CRLF, as used as a newline in DOS). CR sends the cursor back to the front of the line, which is what we see here.. – Charles Duffy Nov 13 '17 at 18:43