find: missing argument to `-exec', even after escaping semicolon

236 Views Asked by At
for i in `ls`; do find /path/to/different/project -name $i -type f -exec sed -i "s/var Handlebars/d" {}; done;

I have tried seemingly everything, including escaping the ; after the {}, escaping both ;'s, escaping the quotes, tweaking the sed command - all to no avail. What gives?

3

There are 3 best solutions below

4
On BEST ANSWER

(Don't use for i in ls. It will fail if any filename includes whitespace, and it is unnecessary. for i in * does exactly what you want, without the need for a subprocess.)

The correct syntax is:

for fn in *; do
  find /path/ -name "$fn" -type f -exec sed ... {} \; ;
done  

\; is an argument to find. Both {} and ; must appear as individual arguments; if you use {}\; the shell will combine those into one argument and find will treat it as a simple argument to sed.

The second ; is a shell metacharacter which terminates the find command. Written as above, on three lines, the ; is unnecessary but if you want a one-liner, it will be needed. If you escape it, as \;, it stops being a shell metacharacter, and is simply passed to find as an argument, where it will create an error.

1
On

the sed command as written will fail, as sed expects 2 args to the s command. Are you attempting to delete all lines where "var Handlebars" exist, if so, then the correct way (with sed) will be

sed '/^.*var Handlebars.*$/d'

which is saying "delete (the 'd' command to sed) any line that contains the string 'var Handlebars'"

The anchors ^ and $ are beginning of line and end of line respectively, with the '.*' meaning zero or more of any character before and after the 'var Handlebars' string.

so your compound command now becomes:

for i in *; do find /path/ -name "$i" -type f -exec sed -i '/^.*var Handlebars.*$/d' {} \; done

4
On

The issue was two-fold. rici was correct that there needed to be an extra semi-colon, but then after that it was still failing unless a space character was inserted between the {} and the \;. The final command looks like this:

for i in `ls`; do find /path/to/different/project -name $i -type f -exec sed -i "/var Handlebars/d" {} \;; done;

Note: I also removed the s (substitution) from the sed command per Cwissy's comment.