I am new to bash scripting. Is it possible to get a value returned on a nested variable? At the command line, the following code will generate desired ouput:

while read line; do echo -e "${line:21}"; done < Albums-linux.txt 

It takes a list of directories for albums and returns a substring of GroupName/albumName. For the next step, I want the result to replace the '/' with '-' I think my syntax should be something like"

while read line; do echo -e  "${"${line:21}"///-}"; done < Albums-linux.txt 

so the output is GroupName-albumName. But I get a result: ${"${line:21}"///-}: bad substitution
I also tried escaping the '/' I wish to substitute by escaping it `${"${line:21}"/\//-}
but still had the same result.

Am I trying to do too much at the command line and I have to write this in a script?


You need a backslash to tell the script to escape the normal use of the next character. Try this:

while read line; do echo -e "${"${line:21}"/\//-}"; done < Albums-linux.txt

Hello dwlamb!

Without your exact example data it's hard to tell for sure, but I believe that bash expects the first parameter to be a variable, which means you can leave out the '$'. This simplified example seems to work for me, and might give you a better idea of how the substitution should look:

echo "$line"
echo "${line/\//-}"

The result:


I hope this helps!

Thanks for the help, Gromit. Your answer worked perfectly. I am wondering though, working at the command line, how would I form the syntax for combining the two actions on line in one pass?

TL;DR version:

try awk -F/ '{print $5 "-" $6}' Albums-linux.txt "$5" and "$6" might need to be tweaked depending on your path.

Now for the full explanation:

Are you asking how to integrate this into your example? My example was just to illustrate how the substitution works, and what syntax the shell expects.

You would simply replace this:


with this:


So it would look more like this:

while read line; do echo "${line/\//-}"; done < Albums-linux.txt

If you have to start the line at position:21, then you might not be able to do it all in one operation using this method. If that's the case, you will want to use something different like sed or awk. Is it safe to assume that Albums-linux.txt contains a list of full paths, and the data that you want starts at :21? You might be able to do something like this, for example, instead:

line="/home/user/audio/GroupName/albumName"; echo $line |awk -F/ '{print $5 "-" $6}'

In this example, we set the field separator in awk to the "/" character. The first field is empty (before the first slash), so if we count the fields in my example, you get GroupName at $5 and albumName at $6. The print statement prints fields 5 and 6 with a hyphen in between, so the result is this:


Which would translate in your original example to something like this self-contained one line awk script:

awk -F/ '{print $5 "-" $6}' Albums-linux.txt

Sorry for the wall of text :) I hope this helps!