glades
glades

Reputation: 4769

Building filename from command outputs results in ambigous redirect error

I want to edit a file and write it to anoter location without .template at the end. To do so, I use two commands in a row which should give me the new file name, but bash doesn't accept it. I heard you should do this with backquotes but I can't get it to work (the first sed is correct don't bother):

sed -E '/^\s*(#.*)?$/d; s/^\s*(\S+)\s+("([^"]*)"|(\S+)).*/s\/\1\/\3\4\/g/' "$file" > `$(basename $file) | sed -E 's/(.*).template$/.translated\1/g')`

I get such errors:

translate: command substitution: line 25: syntax error near unexpected token `)'
translate: command substitution: line 25: `$(basename $file) | sed -E 's/(.*).template$/.translated\1/g')'
translate: line 25: `$(basename $file) | sed -E 's/(.*).template$/.translated\1/g')`: ambiguous redirect

What should the redirect-to-filename part look like?

Upvotes: 0

Views: 43

Answers (1)

Charles Duffy
Charles Duffy

Reputation: 295403

Part 1: Why It Happens

Let's look at why you get a "ambiguous redirect" error.

When you run:

foo > `$(basename $file) | sed -E 's/(.*).template$/.translated\1/g')`

...that's telling the shell to first run a command:

$(basename $file) | sed -E 's/(.*).template$/.translated\1/g'

...and use its output as the redirection target.

However, $(basename $file) | ... is not the same as basename $file | ...! Let's say your file is named /path/to/foo.template. After that first command substitution happens, it's translated to:

foo.template | sed -E 's/(.*).template$/.translated\1/g'

...which is running a command named foo.template and feeding its output to sed.

Do you have a command named foo.template? If you don't, then that just generates an error on stderr, and nothing at all on stdout. Since stdout is what's fed into sed, that means sed receives no input at all, so it writes no output at all, so you have an empty filename.

And trying to redirect to an empty filename... is ambiguous! There's your bug.


Part 2: Doing It Right

I'm assuming both your sed commands do what you want them to do (meaning that you want foo.template to create a file named .footranslated -- if you don't want to create this hidden file, your second sed operation is very wrong).

file_base=${file##*/}
sed -E '/^\s*(#.*)?$/d; s/^\s*(\S+)\s+("([^"]*)"|(\S+)).*/s\/\1\/\3\4\/g/' "$file" \
  >".translated${file_base%.template}"

...or, if your actual intent is to replace the extension .template with an extension .translated, that would instead be:

file_base=${file##*/}
sed -E '/^\s*(#.*)?$/d; s/^\s*(\S+)\s+("([^"]*)"|(\S+)).*/s\/\1\/\3\4\/g/' "$file" \
  >"${file_base%.template}.translated"

Upvotes: 3

Related Questions