0

I am trying to automatically create symlinks to directories and to replace a certain text string (foo) of the original name in the link name (bar). The name of the target directories may contain spaces (e.g. "foo with whitespace").

This is a minimal example:

> ls -Q "foo" "foo with whitespace" 

I am trying the following command (using xargs' -p option to debug/check the result before its execution):

find . -iname "*foo*" -print0 | xargs -0 -I '{}' -p ln -s {} `echo {} | sed -e s#foo#bar#g

My desired outcome is this:

ln -s 'foo with whitespace' 'bar with whitespace' ln -s 'foo' 'bar' 

However the string replacement fails. The actual output looks like this:

ln -s './foo with whitespace' './foo with whitespace'?... ln -s ./foo ./foo?... 

If I use constant strings instead of {}, the string replacement works as intended:

find . -iname "*foo*" -print0 | xargs -0 -I '{}' -p ln -s {} `echo "foo" | sed -e s#foo#bar#g`

ln -s './foo with whitespace' bar?... ln -s ./foo bar?... 

What's my mistake and how do I fix the command invocation?

Edit: Tilman Schmidt's solution works like a charm.

1 Answer 1

1

The command substitution

`echo {} | sed -e s#foo#bar#g` 

is performed only once, before the pipeline composed of the find and xargs commands is run. So sed gets the string {} as input and, not finding foo, outputs it unchanged. Then the shell runs the resulting command line

find . -iname "*foo*" -print0 | xargs -0 -I '{}' -p ln -s {} {} 

So command substitution is the wrong tool here. Try something like

find . -iname "*foo*" -print | while read f; do ln -s "$f" "${f//foo/bar}"; done 

(untested) instead. Note that this won't work if you have filenames containing newlines.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.