0

I have written a recursive function to iterate through directories, iteration should exit when the specified depth is reached. Both the entry directory and maximum depth value are passed as parameters to the function.

perform_fragmented_copy() { 
    echo -e "perform_fragmented_copy: $1 at depth $2"
    while [ "$1" ] && [ "$2" -le $n_max_depth ]; 
    do
        declare -i n_entry_size=$(du -sb $1  | awk '{print $1}')
        if [ $sz_remainig_destination -gt $n_entry_size ]
        then
            echo -e "perform_fragmented_copy: can do the copy";
        else
            echo -e "perform_fragmented_copy: cannot, iterating again";
            declare -i n_curr_depth=$(($2+1))
            perform_fragmented_copy "$1"/* $n_curr_depth
        fi
        shift
    done 
    echo -e "perform_fragmented_copy: exiting: $1 at depth $2"
}

Invoked as

sz_remainig_destination=10000
n_max_depth=5 
perform_fragmented_copy $1 0 

Output is:

perform_fragmented_copy: /home/ROSS-82/ at depth 0
perform_fragmented_copy: cannot, iterating again
perform_fragmented_copy: /home/ROSS-82//82 at depth /home/ROSS-82//ross_reader-82
./ftest.sh: line 69: [: /home/ROSS-82//ross_reader-82: integer expression expected
perform_fragmented_copy: exiting: /home/ROSS-82//82 at depth /home/ROSS-82//ross_reader-82
./ftest.sh: line 69: [: : integer expression expected
perform_fragmented_copy: exiting: 0 at depth

In output at fist recursion $2 is received as integer which is 0

perform_fragmented_copy: /home/ROSS-82/ at depth 0

In output at second recursion $2 is received as $1

perform_fragmented_copy: /home/ROSS-82//82 at depth /home/ROSS-82//ross_reader-82

I have tried many ways to resolve this, and googled for solutions, but no results yet.

tripleee
  • 175,061
  • 34
  • 275
  • 318
Akhil V Suku
  • 870
  • 2
  • 13
  • 34
  • 2
    The wildcard `"$1"/*` expands to more than one argument when the directory `$1` contains more than one file. The simplest fix is probably to reverse the order of the arguments, though you'll probably need to do something useful with the additional arguments, too; what exactly is unclear because you don't explain what this code should do. Tangentially, see also [When to wrap quotes around a shell variable?](https://stackoverflow.com/questions/10067266/when-to-wrap-quotes-around-a-shell-variable) – tripleee Jun 02 '22 at 21:44
  • 1
    Maybe you want to recurse separately for each file: `for f in "$1"/*; do perform_fragmented_copy "$f" $n_curr_depth; done` – Barmar Jun 02 '22 at 21:47
  • it's a bit hard to know for sure what the issue may be since the provided code is not generating the sample output (eg, output does match function's `echo` calls); having said that ... 1st guess would be that `"$1"/*` is expanding to more than one space delimited value (thus pushing `$n_curr_depth` out to position $3, $4 or later); I'd suggest enabling debug mode (`set -xv` at the top level) and/or add some additional `echo` calls to the function (eg, first line of function == `echo $@`) – markp-fuso Jun 02 '22 at 21:48

1 Answers1

2

You should move the depth to the first argument. Then you can shift this out of the argument list before the loop, and the loop processes the remaining arguments with $1 and shift.

perform_fragmented_copy() { 
    depth=$1
    shift
    echo -e "perform_fragmented_copy: $@ at depth $depth"

    if [ "$depth" -ge "$n_max_depth" ]
    then return
    fi
    declare -i n_curr_depth=$(($depth+1))

    while [ $# -gt 0 ]; 
    do
        declare -i n_entry_size=$(du -sb "$1" | awk '{print $1}')
        if [ $sz_remainig_destination -gt $n_entry_size ]
        then
            echo -e "perform_fragmented_copy: can do the copy";
        else
            echo -e "perform_fragmented_copy: cannot, iterating again";
            perform_fragmented_copy $n_curr_depth "$1"/* 
        fi
        shift
    done 
    echo -e "perform_fragmented_copy: exiting: at depth $depth"
}

You can't refer to $1 in the exiting message at the end, because the loop ends when all the parameters have been shifted away. The loop ends when $1 is empty.

Barmar
  • 741,623
  • 53
  • 500
  • 612