Bash: get all paths from path

北城余情 提交于 2019-12-24 10:53:43

问题


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


回答1:


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.




回答2:


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/



回答3:


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.




回答4:


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==


来源:https://stackoverflow.com/questions/25447010/bash-get-all-paths-from-path

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!