1

I am not too deep in the material and rarely use Bash scripts. Even with some research, I couldn't quickly learn everything in Bash so that I could search an entire directory with its sub-directories for files and then output their type. I've now gotten a bit into the direction of functions, but again don't quite know how to do this recursively. Also, I want to consider only files and not folders. Here is something I have already done on my own:

for item in "$1"/*
do
    if ! [ -d $item ]; then
        echo $(file $item)
    fi
done;

So when the script is called, the path is passed as an argument. The path is then searched for non-directories and their type is output with the command file. But how is this recursive and also implementable for sub-directories? I have also tried it by iterating over ls -R, but then names of folders are still appended and I can no longer check via my way if it is a folder or a file. Edit: I can't use find!

I am glad about any help!

Lauren Yim
  • 12,700
  • 2
  • 32
  • 59
zuzuri
  • 45
  • 6
  • 1
    try this `find . -type f -exec file {} +` – Fravadona Apr 25 '22 at 20:42
  • Sorry, I had forgotten to write that. I can not use find :/ – zuzuri Apr 25 '22 at 20:46
  • Huh! What version of bash are targeting? bash-4+? – Fravadona Apr 25 '22 at 20:50
  • It's not necessarily about that, but rather about learning and practicing. With find it would be just a one-liner, yes – zuzuri Apr 25 '22 at 20:52
  • `find` is definitely the best way to do this. Just use `find`. Using recursive glob expansion on a large directory tree (`file **`) could exceed the system's `ARG_MAX` when passing all those files to `file`. `find` handles this for you. You could use `xargs` to manage it but I can't see a good reason to, except maybe to run parallel `file` processes. – dan Apr 25 '22 at 21:12

3 Answers3

2

You can use bash extended globbing capabilities:

$ shopt -s dotglob globstar
$ for i in **/*; do [ -d "$i" ] && continue; file "$i"; done
Arkadiusz Drabczyk
  • 11,227
  • 2
  • 25
  • 38
  • First of all, thank you for the solution suggestion. With a small optimization of the path specification in for it works, but I am confused. Now where is globstar used and is this really recursive? I don't see a self call – zuzuri Apr 25 '22 at 21:31
  • `globstar` is Bash option, read about it in `man bash`. What's _self call_? – Arkadiusz Drabczyk Apr 25 '22 at 21:32
  • You can get more useful help using `help set` and `help shopt`, by the way. – Mark Setchell Apr 25 '22 at 21:35
  • Thanks! Recursion describes that a function calls itself again in order to reach the desired goal – zuzuri Apr 25 '22 at 21:37
  • Somewhat simplified: `for i in **/*; do [ ! -d "$i" ] && file "$i"; done` – Cyrus Apr 25 '22 at 23:18
0

This may help: How to recursively list subdirectories in Bash without using "find" or "ls" commands?

That said, I modified it to accept user input as follows:

#!/bin/bash

recurse() {
 for i in "$1"/*;do
    if [ -d "$i" ];then
        echo "dir: $i"
        recurse "$i"
    elif [ -f "$i" ]; then
        echo "file: $i"
    fi
 done
}

recurse $1

If you didn't want the files portion (which it appears you don't) then just remove the elif and line below it. I left it in as the original post had it also. Hope this helps.

graih
  • 30
  • 3
  • Thank you very much, but I have the following problem: `if ! [ -d "$i" ]; then echo $(file §i) else recurse "$i"' My output is 3x directory, which isn't true and I need files, nit directories :/ – zuzuri Apr 25 '22 at 21:56
0

Suggesting

   file $(find -type f 2>/dev/null)

Explanation:

  1. find command that search recursively into current folder.

  2. Filter only files from find command: -type f .

  3. Ignore any find permission/access errors with 2>/dev/null

  4. Run file command on each found file.

Dudi Boy
  • 4,551
  • 1
  • 15
  • 30