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!