Perform an action in every sub-directory using Bash

前端 未结 9 538
迷失自我
迷失自我 2020-12-04 05:46

I am working on a script that needs to perform an action in every sub-directory of a specific folder.

What is the most efficient way to write that?

相关标签:
9条回答
  • 2020-12-04 06:06

    The simplest non recursive way is:

    for d in */; do
        echo "$d"
    done
    

    The / at the end tells, use directories only.

    There is no need for

    • find
    • awk
    • ...
    0 讨论(0)
  • 2020-12-04 06:07

    Use find command.

    In GNU find, you can use -execdir parameter:

    find . -type d -execdir realpath "{}" ';'
    

    or by using -exec parameter:

    find . -type d -exec sh -c 'cd -P "$0" && pwd -P' {} \;
    

    or with xargs command:

    find . -type d -print0 | xargs -0 -L1 sh -c 'cd "$0" && pwd && echo Do stuff'
    

    Or using for loop:

    for d in */; { echo "$d"; }
    

    For recursivity try extended globbing (**/) instead (enable by: shopt -s extglob).


    For more examples, see: How to go to each directory and execute a command? at SO

    0 讨论(0)
  • 2020-12-04 06:10

    You could try:

    #!/bin/bash
    ### $1 == the first args to this script
    ### usage: script.sh /path/to/dir/
    
    for f in `find . -maxdepth 1 -mindepth 1 -type d`; do
      cd "$f"
      <your job here>
    done
    

    or similar...

    Explanation:

    find . -maxdepth 1 -mindepth 1 -type d : Only find directories with a maximum recursive depth of 1 (only the subdirectories of $1) and minimum depth of 1 (excludes current folder .)

    0 讨论(0)
  • 2020-12-04 06:13

    This will create a subshell (which means that variable values will be lost when the while loop exits):

    find . -type d | while read -r dir
    do
        something
    done
    

    This won't:

    while read -r dir
    do
        something
    done < <(find . -type d)
    

    Either one will work if there are spaces in directory names.

    0 讨论(0)
  • 2020-12-04 06:17

    A version that avoids creating a sub-process:

    for D in *; do
        if [ -d "${D}" ]; then
            echo "${D}"   # your processing here
        fi
    done
    

    Or, if your action is a single command, this is more concise:

    for D in *; do [ -d "${D}" ] && my_command; done
    

    Or an even more concise version (thanks @enzotib). Note that in this version each value of D will have a trailing slash:

    for D in */; do my_command; done
    
    0 讨论(0)
  • 2020-12-04 06:20

    Handy one-liners

    for D in *; do echo "$D"; done
    for D in *; do find "$D" -type d; done ### Option A
    
    find * -type d ### Option B
    

    Option A is correct for folders with spaces in between. Also, generally faster since it doesn't print each word in a folder name as a separate entity.

    # Option A
    $ time for D in ./big_dir/*; do find "$D" -type d > /dev/null; done
    real    0m0.327s
    user    0m0.084s
    sys     0m0.236s
    
    # Option B
    $ time for D in `find ./big_dir/* -type d`; do echo "$D" > /dev/null; done
    real    0m0.787s
    user    0m0.484s
    sys     0m0.308s
    
    0 讨论(0)
提交回复
热议问题