Say I have the path gui/site/junior/profile.py
How do I get this?:
gui
gui/site
gui/site/junior
Bonus if you tell me how to loop through each path :D
Say I have the path gui/site/junior/profile.py
How do I get this?:
gui
gui/site
gui/site/junior
Bonus if you tell me how to loop through each path :D
You can loop with awk:
awk 'BEGIN{FS=OFS="/"}
{ for (i=1; i<=NF; i++) {
for (j=1; j<i; j++)
printf "%s/", $j
printf "%s\n", $i
}
}' <<< "gui/site/junior/profile.py"
See as one liner:
$ awk 'BEGIN{FS=OFS="/"}{for (i=1; i<=NF; i++) { for (j=1; j<i; j++) printf "%s%s", $j, OFS; printf "%s\n", $i}}' <<< "gui/site/junior/profile.py"
gui
gui/site
gui/site/junior
gui/site/junior/profile.py
This takes advantage of NF
, which counts how many fields the current record has. Based on that, it loops from the first up to the last one, printing every time first up to that value.
a dash answer:
path="gui/site with spaces/junior/profile.py"
oldIFS=$IFS
IFS=/
set -- $(dirname "$path")
IFS=$oldIFS
accumulated=""
for dir in "$@"; do
accumulated="${accumulated}${dir}/"
echo "$accumulated"
done
gui/
gui/site with spaces/
gui/site with spaces/junior/
You can use the shell's built-in splitting facilities. IFS
specifies what to split on.
oldIFS=$IFS
IFS=/
set -f
set -- $path
set +f
IFS=$oldIFS
for component in "$@"; do
echo "$component"
done
This could be refactored in many ways, but I want the change to IFS
to only govern the actual splitting.
The use of set
to split a string into positional parameters is slightly obscure, but well worth knowing.
You should properly take care to unset IFS
if it was originally unset, but I'm skimping on that.
Perl variant:
perl -F/ -nlE 'say join("/",@F[0..$_])||"/"for(0..$#F-1)' <<< "gui/site with spaces/junior/profile.py"
produces
gui
gui/site with spaces
gui/site with spaces/junior
if you have NULL separates pathnames, you can add 0
to arguments:
perl -F/ -0nlE 'say join("/",@F[0..$_])||"/"for(0..$#F-1)'
^
e.g from
printf "/some/path/name/here/file.py\0" | perl -F/ -nlE 'say join("/",@F[0..$_])||"/"for(0..$#F-1)'
# ^^
produces
/
/some
/some/path
/some/path/name
/some/path/name/here
For iterating over the paths, you can use the next:
origpath="some/long/path/here/py.py"
do_something() {
local path="$1"
#add here what you need to do with the partial path
echo "Do something here with the ==$path=="
}
while read -r part
do
do_something "$part"
done < <(perl -F/ -nlE 'say join("/",@F[0..$_])||"/"for(0..$#F-1)' <<< "$origpath")
it produces:
Do something here with the ==some==
Do something here with the ==some/long==
Do something here with the ==some/long/path==
Do something here with the ==some/long/path/here==