0

i have the following script:

    #!/bin/bash
    for ((i=1; i<=$#; i++));
    do
       if [ ! -d $i ]
       then
          echo $i its not a directory >> file.txt
       else
          DIRECTORY=$(ls -l $i | grep ^d | wc -l)
          LINK=$(find $i -type l | wc -l)
          FILE=$(ls -A $i | wc -l)

          echo `date "+%H:%M:%S %d-%m-%y"` directory $i file count: $FILE link count: $LINK subdirectory count: $DIRECTORY >> file.txt

       fi
    done

this script count the subdirectories, links and files from a directory entered by parameter(it can be more than 1).

i am struggling with the loop, it returns "echo $i its not a directory" reading $i as 1 instead of $1, i do understand why it does that but i am starting with scripts and don't know how to fix this. i think a "while" can be a substitute for that "for" but don't know how to use it properly.

thanks for the help!

  • just tried it, returns "$i is not a directory" – Kuma May 26 '16 at 19:24
  • You're never actually looking at the arguments themselves, just numbers from 1 to n (where n is the number of arguments), and testing those numbers and not the filenames you think you're testing. – DopeGhoti May 26 '16 at 19:37
  • i saw that, but i didn't have a clue on how to solve it, ill have to work harder on scripts, thanks. – Kuma May 26 '16 at 19:53
  • 1
    As mentioned, you can use indirection (${!i}) also, but in your case, just looking at the arguments themselves ($@) is simpler. – DopeGhoti May 26 '16 at 19:55
  • Don't parse ls. Use find instead. e.g. DIRECTORY=$(find "$i" -maxdepth 1 -type d ! -name '.*' -print0 | sed -z -n -e '$=' (requires a recent GNU sed for the -z option). and use something similar for symlinks (-type l) and regular files (-type f). The ! -name '.*' excludes hidden dot-files/dirs from being counted. – cas May 27 '16 at 9:04
1

You are looping from 1 to [number of arguments], and then testing if each of those numbers is in fact a directory. It might be simpler to do something like:

#!/bin/bash
for item in "$@"; do  # iterate over the arguments themselves
    if [[ ! -d "$item" ]]; then
        echo "$item is not a directory" >> file.txt
    else
        DIRECTORY=$(ls -l $item | grep ^d | wc -l)
        LINK=$(find $item -type l | wc -l)
        FILE=$(ls -A $item | wc -l)

        echo `date "+%H:%M:%S %d-%m-%y"` directory $item file count: $FILE link count: $LINK subdirectory count: $DIRECTORY >> file.txt
    fi
done
1

What you are trying to do is called variable indirection—you want to refer to the variable whose name is stored inside another variable. This is possible in bash—just refer to "${!i}" instead of $i.

Also note the importance of double quotes around your variables.

That said...you can simplify your script drastically. For instance, here is a one-liner that does nearly everything you are trying to do with your script.

  • +1. that one-liner in the else clause of @dopeghoti's bash script (and run date ... before the one-liner) would be good. and move the >> file.txt to the end of the done line. – cas May 27 '16 at 16:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.