1

I want to find all .mb files in multiple big folders, but I only want to return one file from each folder if there are many files matching my search criterion.

folder structure

..
--abc
    |_scenes
    |    |__  file1.mb
    |    |__  file2.mb
    |...
--def
    |_scenes
    |    |__  file3.mb
    |    |__  file4.mb
    |...

if I do

find /net/*/scenes -maxdepth 1 -type f -size +200M

It returns all

file1.mb
file2.mb
file3.mb
file4.mb

How can I return only file1.mb and file3.mb?

1
  • I updated my solution to use find instead of a bash loop - double find.
    – igal
    Jun 15, 2018 at 17:06

3 Answers 3

1

find + awk solution:

find /net/*/scenes -maxdepth 1 -type f -name "*.mb" \
| awk -F'/' '{ fn = $NF; $NF = "" }!a[$0]++{ print $0 fn }' OFS='/'
  • -F'/' and OFS='/' - stand for input and output field separator
  • fn = $NF - storing the last field value (i.e. a filename) into variable fn
  • !a[$0]++{ print $0 fn } - on the 1st occurrence of unique directory path (presented by $0) print the line(the whole filepath)

Or using GNU coreutils pipeline:

find /net/*/scenes -maxdepth 1 -type f -name "*.mb" -printf "%H %p\n" \
| sort -k1,1 -u | cut -d' ' -f2
2
  • thanks! can you explain the awk part?
    – Shuman
    Jun 15, 2018 at 16:52
  • @Shuman, see my explanation Jun 15, 2018 at 17:01
0

Your new edit specifies that you're using tcsh - I'd originally assumed you were using bash. You could call find from within a find -exec invocation and pipe each internal find invocation to head to extract the first result, e.g.

find /net/* -maxdepth 1 -exec tcsh -c "find {} -maxdepth 1 -type f -name '*.mb' -size +200M | head -1" \;

Here's a little example demonstration:

# Create the directory structure
mkdir -p test/abc/scenes
mkdir -p test/def/scenes

# Create example data files
dd if=/dev/zero of=abc/scenes/file1.mb bs=201M count=1
dd if=/dev/zero of=abc/scenes/file2.mb bs=201M count=1
dd if=/dev/zero of=def/scenes/file3.mb bs=201M count=1
dd if=/dev/zero of=def/scenes/file4.mb bs=201M count=1

# Execute the find command
find ./* -maxdepth 1 -exec tcsh -c "find {} -maxdepth 1 -type f -name '*.mb' -size +200M | head -1" \;

This yields the following output:

./abc/scenes/file1.mb
./def/scenes/file3.mb

Originally the question didn't specify tcsh. In bash, you could call find from within a loop and pipe each find invocation to head to extract the first result, e.g.

for directory in /net/*/scenes; do
    find "${directory}" -maxdepth 1 -type f -name '*.mb' -size +200M | head -1;
done

Here's a little example demonstration:

# Create the directory structure
mkdir -p test/abc/scenes
mkdir -p test/def/scenes

# Create example data files
dd if=/dev/zero of=abc/scenes/file1.mb bs=201M count=1
dd if=/dev/zero of=abc/scenes/file2.mb bs=201M count=1
dd if=/dev/zero of=def/scenes/file3.mb bs=201M count=1
dd if=/dev/zero of=def/scenes/file4.mb bs=201M count=1

# Execute the find command
for directory in ./*/scenes; do
    find "${directory}" -maxdepth 1 -type f -name '*.mb' -size +200M | head -1;
done

This yields the following output:

./abc/scenes/file1.mb
./def/scenes/file3.mb
0

Using 2 find commands first to find directories, then to search in each of them:

while read dir; do find "$dir" -name "*.mb" -maxdepth 1 | head -1 ; done << EOF
$(find /net/*/scenes -type d)
EOF

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .