Assigning only part of a string to a variable in bash

Solution 1:

Using bash's string manipulation:

$ a=/home/myusername/folder1/folder2/folder3
$ echo "${a#/*/*/}"
folder1/folder2/folder3

So, the string you want would be (adding back the leading slash):

b="/${a#/*/*/}"

For a variable a, ${a#foo} will remove the shortest string matching foo from the start of a. So, we remove the shortest string containing three / (including the leading slash in the path), to remove the first two components of the absolute path.

Solution 2:

Here is an example using cut

echo "/home/myusername/folder1/folder2/folder3" | cut -d '/' -f4- 

folder1/folder2/folder3

If you need the leading / you could append | sed 's/^/\//' to the end of your line.

You need -f4- because -d '/' tells cut to use / as a delimiter between fields. So the first field comes before the first delimiter, in this case the first field is empty. So folder1 is the 4th field and -f4- tells cut to use all fields from the 4th onwards.

Solution 3:

You can use bash parameter expansion like so:

target_path=/home/username/folder1/folder2/folder3
myvar="/${target_path#/*/*/}"

After this:

echo $myvar

gives:

/folder1/folder2/folder3

It works by removing the first match of the pattern /*/*/ from your target_path variable, by using the ${target_path#pattern} shell parameter expansion syntax. Unfortunately this removes the first / character, which is why that character must be explicitly included while setting the myvar variable.

Warning: You should check that your target_path variable contains some characters, and is longer than two path segments before using this method. For instance if target_path=/home/username/, then myvar=/. This could be dangerous to your system if you're running something like rm -rf "$myvar"*. Don't try this!