Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I know that I can remove substrings from the front of a variable:

X=foobarbaz
echo ${X#foo}       # barbaz

...and from the back of a variable:

echo ${X%baz}       # foobar

How do I combine the two? I've tried:

echo ${{X#foo}%baz}    # "bad substitution"
echo ${${X#foo}%baz}   # "bad substitution"
echo ${X#foo%baz}      # foobarbaz

I don't think I can use an intermediate variable, because this is being used in find -exec, in something like the following:

find ./Source -name '*.src' \
    -exec bash -c 'myconvert -i "{}" -o "./Dest/${0#./Source/%.src}.dst"' {} \;
share|improve this question
    
Could the inner brace be an alias ? I'm not so good with Bash aliases. – Arif Burhan yesterday
    
Note, before bash had such string manipulation we used expr (which uses an anchored regexp not globs). Eg expr "foobarbaz" : 'foo\(.*\)baz$' returns the captured "bar". – meuh yesterday
up vote 5 down vote accepted

I don't think that's possible (but would love to be proved wrong). However, you can use an intermediate variable. The bash -c run by -exec is just a bash instance, like any other:

$ find . -type f
./foobarbaz
$ find . -type f -exec bash -c 'v=${0#./foo}; echo ${v%baz}'  {} \;
bar

So I see no reason why this wouldn't work (if I understood what you're trying to do correctly):

find ./Source -name '*.src' \
     -exec bash -c 'v=${0%.src}; \ 
        myconvert -i "{}" -o "./Dest/${v#./Source/}.dst"' {} \;
share|improve this answer
    
That seems to work. Thanks. – Roger Lipscombe yesterday

The usual way is to do it in two steps:

x=foobarbaz
y=${x#foo}       # barbaz
z=${y%baz}       # bar

As this are "Parameter Expansions", a "Parameter" (variable) is needed to be able to perform any substitution. That means that y and z are needed. Even if they could be the same variable:

x=foobarbaz
x=${x#foo}       # barbaz
x=${x%baz}       # bar

find ./Source/ -name '*.src' -exec \
    bash -c '
        x=${1#./Source/}
        myconvert -i "$1" -o "./Dest/${x%.src}.dst"
    ' shname {} \;

Where shname is parameter $0 and the next {} is parameter $1 to the bash call.


A simpler alternative is to do a cd ./Source at the begining to avoid removing that part later. Something like:

cd ./Source                 ### Maybe test that it exist before cd to it.
shopt -s extglob nullglob   ### Make sure that correct options are set.

for f in *.src **/*.src; do
    echo \
    myconvert -i "$f" -o "./Dest/${f%.src}.dst"
done

Once you are convinced that it does what you want, comment out the echo.

share|improve this answer

I always do it one step at a time:

X=foobarbaz; X="${X#foo}"; X="${X%baz}"
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.