Looping over directories in Bash

前端 未结 3 1625
天命终不由人
天命终不由人 2020-12-09 10:24

I have a fundamental question about how bash works, and a related practical question.

Fundamental question: suppose I am in a directory that has three subdirectories

相关标签:
3条回答
  • 2020-12-09 10:52

    Well, you know what you are seeing is not what you are expecting. The output you are seeing is not from the echo command, but from the dir command.

    Try the following:

    ls -1 | while read line; do 
    
       if [-d "$line" ] ; then 
          echo $line
       fi
    
    done
    
    
    for files in $(ls) ; do
    
       if [-d "$files" ] ; then 
          echo $files
       fi
    
    done
    
    0 讨论(0)
  • 2020-12-09 10:53

    This should work:

    shopt -s nullglob   # empty directory will return empty list
    for dir in ./*/;do
        echo "$dir"         # dir is directory only because of the / after *
    done
    

    To be recursive in subdirectories too, use globstar:

    shopt -s globstar nullglob
    for dir in ./**/;do
        echo "$dir" # dir is directory only because of the / after **
    done
    

    You can make @Adrian Frühwirths' method to be recursive to sub-directories by using globstar too:

    shopt -s globstar
    for dir in ./**;do
        [[ ! -d $dir ]] && continue # if not directory then skip
        echo "$dir"
    done
    

    From Bash Manual:

    globstar

    If set, the pattern ‘**’ used in a filename expansion context will match all files and zero or more directories and subdirectories. If the pattern is followed by a ‘/’, only directories and subdirectories match.

    nullglob

    If set, Bash allows filename patterns which match no files to expand to a null string, rather than themselves.

    0 讨论(0)
  • 2020-12-09 11:03

    Never ever parse the output of ls like this (Why you shouldn't parse the output of ls(1)).

    Also, your syntax is wrong. You don't mean (), you mean $().

    That being said, to loop over directories starting with W you would do (or use the find command instead, depending on your scenario):

    for path in /my/path/W*; do
        [ -d "${path}" ] || continue # if not a directory, skip
        dirname="$(basename "${path}")"
        do_stuff
    done
    

    As for the output you get from the evil ls-loop, it should not look like that. This is the expected output and demonstrates why you do not want to use ls in the first place:

    $ find
    .
    ./c
    ./a
    ./foo bar
    ./b
    
    $ type ls
    ls is hashed (/bin/ls)
    
    $ for x in $(ls); do echo "${x}"; done
    a
    b
    c
    foo
    bar
    
    0 讨论(0)
提交回复
热议问题