0

In the directory below I want the list of files nested inside numbered directories at depth 1, which in this case are 6 to 11.

$ ls *
1.org   2.MOV  3.MOV  4-1.MOV  5-1.mp4  5-2.MOV  5-2.org~  9-2.MOV
1.org~  2.org  3.org  4-1.org  5-1.org  5-2.org  9-1.MOV

10:
10.mp4

11:
11.MOV

6:
6.mp4

7:
7.MOV

8:
8.MOV

For example, I want 6.mp4 to be returned, not 2.MOV. First attempt (I know it is imperfect as it leaves out 10 11). I tried using depth but there a positional problems.

$ find . -type f -path [^0-9]/* 
./11/11.MOV
./5-1.mp4
./5-1.org
./4-1.MOV
./10/10.mp4
./7/7.MOV
./2.org
./3.org
./2.MOV
./5-2.org
./3.MOV
./5-2.org~
./5-2.MOV
./1.org
./1.org~
./8/8.MOV
./4-1.org
./9-2.MOV
./9-1.MOV
./6/6.mp4
  • 2
    what about ls [0-9]*/* – Jasen Mar 3 at 1:12
  • $ find . -type f -path [^0-9]*/* still returns file that are at the base of the $PWD, not just nested in the first level numbered directories. – Erwann Mar 3 at 1:38
  • Do the directories only contain single numbers or are there directories that contain other patterns such as letters, hyphens, dashed, multiple numbers, etc? – Nasir Riley Mar 3 at 2:06
  • All that the directory contains in the example at hand is shown by ls in the question statement. Upon reflection I realize I should have put ^ outside the square brackets. Anchoring, not excluding. Like this: $ find . -type f -path '^[0-9]*/*', which returns nothing... – Erwann Mar 3 at 3:02
  • Try my updated answer. I have fixed the mistake and specified {6..11} which uses brace expansion. – Nasir Riley Mar 3 at 5:30
0
ls */

This would list the contents of all the non-hidden subdirectories in the current directory. Since you only seem to have subdirectories with numeric names, this will show the contents of these.

The shell globbing pattern * would expand to all non-hidden names in the current directory. Adding a / at the end of the pattern forces the pattern to expand to only directories (since non-directories can't have / in their names).

With the zsh shell, the following filename globbing pattern would expand to only regular files in each subdirectory

*/*(.)

To do something with those names that matches, you would loop over the expansion of that glob pattern:

for pathname in */*(.); do
    # use "$pathname" here
done

In bash or sh, you would call a small script from find instead:

find . -mindepth 2 -maxdepth 2 -type f -exec sh '
    for pathname do
        # use "$pathname" here
    done' sh {} +

But that's really just a fancy way of writing

for pathname in */*; do
    [ ! -f "$pathname" ] && continue
    # use "$pathname" here
done

except that the find variation would skip symbolic links to regular files and include hidden names (set the dotglob shell option in bash to include these).

Again, this would do what you wanted (look in directories with numeric names) because you appear to only have subdirectories with numeric names.

Assuming that there may be other subdirectories too,

for pathname in */*; do
    [ ! -f "$pathname" ] && continue
    case $(dirname "$pathname") in
        *[!0-9]*) continue
    esac
    # use "$pathname" here
done

or, with bash,

for pathname in */*; do
    if [ ! -f "$pathname" ] ||
       [[ $(dirname "$pathname") == *[!0-9]* ]]
    then
        continue
    fi
    # use "$pathname" here
done

These loops would loop over all the names in the subdirectories, but would skip any name not referring to a regular file (or a symbolic link to one), and would also skip any file in a subdirectory whose name contains anything that is not a digit.

With the extglob shell option in bash, you could make that a bit shorter:

shopt -s exglob
for pathname in +([0-9])/*
    [ ! -f "$pathname" ] && continue
    # use "$pathname" here
done

The pattern +([0-9)/ would expand to names of directories that only have digits in their names. This would also work in zsh if the KSH_GLOB option was set instead of extglob.

With GNU find, you could obviously pick out your numeric directories and then loop over their contents:

find . -maxdepth 1 -type d -regex '.*/[0-9]+$' -exec sh '
    for dirpath do
        for pathname in "$dirpath"/*; do
            [ ! -f "$pathname" ] && continue
            # use "$pathname" here
        done
    done' sh +

but I don't generally suggest using regular expressions on filenames or directory names since they are mainly for matching text in text files. GNU find obviously supports matching pathnames with regular expressions, because GNU software tries to be as convenient as possible.

  • I think it boils down to regex rather than pathname. Thank you. $ find . -regex './[0-9]+/*' ./11 ./10 ./7 ./8 ./6 – Erwann Mar 4 at 1:59
  • PS: I would have expected the last cmd to return the content of the numeric directories... – Erwann Mar 4 at 2:05
1

You are getting those results because find looks at everything contained in the current directory unless one specifies otherwise. If you just want to see files inside of the numbered directories named 6-11 which are in the current directory then all you need is this:

As there is no 9, you can use this one:

find {6,7,8,10,11} -type f

That will expand only the included numbers.

If you had from 6-11 with all numbers in between:

find {6..11} -type f

That will look only in the directories named 6-11 and return the files inside.

If those are the only directories inside of the current directory, which it appears as so according to your results, then you can also just do this:

find . -mindepth 2 -type f

That will tell it to begin one level below the current directory or two levels deep.

  • I would use this for the simple example at hand, except I get this: $ find {6-11} -type f find: ‘{6-11}’: No such file or directory. I wonder – Erwann Mar 3 at 3:03
  • Yes, {6-11}, but it will look for 9, which in this case does not exist. I was wishfully thinking [0-9]. Alas, find: ‘[0-9]’: No such file or directory – Erwann Mar 3 at 3:22
  • @Erwann I have updated the answer with brace expansion of {6..11}. You said that the directories are named 6-11 in your question. The {6-11} is a typo on my part due to me reading 6-11 shakes head. – Nasir Riley Mar 3 at 3:33
  • @Erwann Have you tried using find * -maxdepth 1 -type f inside the main directory where all the sub directories reside. The above find traverses the directories and looks for files which are a level 1 of the directory structure. Output should be something like this: [root@c7-server directory]# find * -maxdepth 1 -type f 1.org/file2 – Atul Mar 3 at 5:32
  • @Atul Your first command would only find files in the working directory which isn't wanted. 1.org is a file and not a directory so it wouldn't give that output anyway. – Nasir Riley Mar 3 at 6:11

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.