Finding all files with a given extension whose base name is the name of the parent directoryHow to exclude a list of full directory paths in find command on SolarisFind files that have a confirmed duplicate in same directory recursively'Tar' the result of a 'find', preserving the directory structureRename all files in directory while preserving any file extensionHow to find all files except with PNG, JPG extension?How to find and print specific file paths with exclusions?bash - Find All Files with Same Name Regardless of ExtensionFind all files with the same namefind: exclude n different directories and m different files present at any level but include few files from some excluded directoriesRenaming many files to their parent directory name

Multi tool use
Multi tool use

What's the Difference between Two Single-Quotes and One Double-Quote?

Where is the encrypted mask value?

Why do they consider the Ori false gods?

I unknowingly submitted plagiarised work

What are these (utility?) boxes at the side of the house?

How long does it take to crack RSA 1024 with a PC?

What do different value notes on the same line mean?

Does this degree 12 genus 1 curve have only one point over infinitely many finite fields?

What is the difference between nullifying your vote and not going to vote at all?

Tic-tac-toe for the terminal, written in C

Mother abusing my finances

Crossing US border with music files I'm legally allowed to possess

Command to Search for Filenames Exceeding 143 Characters?

Why is this Simple Puzzle impossible to solve?

Employer demanding to see degree after poor code review

I think I may have violated academic integrity last year - what should I do?

Plot twist where the antagonist wins

How to capture more stars?

Why are these traces shaped in such way?

General purpose replacement for enum with FlagsAttribute

Which noble houses were destroyed during the Game of Thrones?

Windows 10 Programs start without visual Interface

How can I get exact maximal value of this expression?

Employer asking for online access to bank account - Is this a scam?



Finding all files with a given extension whose base name is the name of the parent directory


How to exclude a list of full directory paths in find command on SolarisFind files that have a confirmed duplicate in same directory recursively'Tar' the result of a 'find', preserving the directory structureRename all files in directory while preserving any file extensionHow to find all files except with PNG, JPG extension?How to find and print specific file paths with exclusions?bash - Find All Files with Same Name Regardless of ExtensionFind all files with the same namefind: exclude n different directories and m different files present at any level but include few files from some excluded directoriesRenaming many files to their parent directory name






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








9















I want to recursively look for every *.pdf file in a directory ~/foo whose base name matches the name of the file's parent directory.



For instance, suppose that the directory structure ~/foo looks like this



foo
├── dir1
│   ├── dir1.pdf
│   └── dir1.txt
├── dir2
│   ├── dir2.tex
│   └── spam
│   └── spam.pdf
└── dir3
├── dir3.pdf
└── eggs
└── eggs.pdf


Running my desired command would return



~/foo/dir1/dir1.pdf
~/foo/dir2/spam/spam.pdf
~/foo/dir3/dir3.pdf
~/foo/dir3/eggs/eggs.pdf


Is this possible using find or some other core utility? I assume this is doable using the -regex option to find but I'm not sure how to write the correct pattern.










share|improve this question
























  • Yes, I'll mock up an example now.

    – Brian Fitzpatrick
    May 21 at 5:10






  • 1





    @Inian Added an example. Does this help?

    – Brian Fitzpatrick
    May 21 at 5:15

















9















I want to recursively look for every *.pdf file in a directory ~/foo whose base name matches the name of the file's parent directory.



For instance, suppose that the directory structure ~/foo looks like this



foo
├── dir1
│   ├── dir1.pdf
│   └── dir1.txt
├── dir2
│   ├── dir2.tex
│   └── spam
│   └── spam.pdf
└── dir3
├── dir3.pdf
└── eggs
└── eggs.pdf


Running my desired command would return



~/foo/dir1/dir1.pdf
~/foo/dir2/spam/spam.pdf
~/foo/dir3/dir3.pdf
~/foo/dir3/eggs/eggs.pdf


Is this possible using find or some other core utility? I assume this is doable using the -regex option to find but I'm not sure how to write the correct pattern.










share|improve this question
























  • Yes, I'll mock up an example now.

    – Brian Fitzpatrick
    May 21 at 5:10






  • 1





    @Inian Added an example. Does this help?

    – Brian Fitzpatrick
    May 21 at 5:15













9












9








9


1






I want to recursively look for every *.pdf file in a directory ~/foo whose base name matches the name of the file's parent directory.



For instance, suppose that the directory structure ~/foo looks like this



foo
├── dir1
│   ├── dir1.pdf
│   └── dir1.txt
├── dir2
│   ├── dir2.tex
│   └── spam
│   └── spam.pdf
└── dir3
├── dir3.pdf
└── eggs
└── eggs.pdf


Running my desired command would return



~/foo/dir1/dir1.pdf
~/foo/dir2/spam/spam.pdf
~/foo/dir3/dir3.pdf
~/foo/dir3/eggs/eggs.pdf


Is this possible using find or some other core utility? I assume this is doable using the -regex option to find but I'm not sure how to write the correct pattern.










share|improve this question
















I want to recursively look for every *.pdf file in a directory ~/foo whose base name matches the name of the file's parent directory.



For instance, suppose that the directory structure ~/foo looks like this



foo
├── dir1
│   ├── dir1.pdf
│   └── dir1.txt
├── dir2
│   ├── dir2.tex
│   └── spam
│   └── spam.pdf
└── dir3
├── dir3.pdf
└── eggs
└── eggs.pdf


Running my desired command would return



~/foo/dir1/dir1.pdf
~/foo/dir2/spam/spam.pdf
~/foo/dir3/dir3.pdf
~/foo/dir3/eggs/eggs.pdf


Is this possible using find or some other core utility? I assume this is doable using the -regex option to find but I'm not sure how to write the correct pattern.







find






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 22 at 7:39









user7761803

1433




1433










asked May 21 at 4:49









Brian FitzpatrickBrian Fitzpatrick

96721123




96721123












  • Yes, I'll mock up an example now.

    – Brian Fitzpatrick
    May 21 at 5:10






  • 1





    @Inian Added an example. Does this help?

    – Brian Fitzpatrick
    May 21 at 5:15

















  • Yes, I'll mock up an example now.

    – Brian Fitzpatrick
    May 21 at 5:10






  • 1





    @Inian Added an example. Does this help?

    – Brian Fitzpatrick
    May 21 at 5:15
















Yes, I'll mock up an example now.

– Brian Fitzpatrick
May 21 at 5:10





Yes, I'll mock up an example now.

– Brian Fitzpatrick
May 21 at 5:10




1




1





@Inian Added an example. Does this help?

– Brian Fitzpatrick
May 21 at 5:15





@Inian Added an example. Does this help?

– Brian Fitzpatrick
May 21 at 5:15










6 Answers
6






active

oldest

votes


















16














With GNU find:



find . -regextype egrep -regex '.*/([^/]+)/1.pdf'



  • -regextype egrep use egrep style regex.


  • .*/ match grand parent directires.


  • ([^/]+)/ match parent dir in a group.


  • 1.pdf use backreference to match file name as parent dir.

update



One (myself for one) might think that .* is greedy enough, it's unnecessary to exclude / from parent matching:



find . -regextype egrep -regex '.*/(.+)/1.pdf'


Above command won't work well, because it mathches ./a/b/a/b.pdf:




  • .*/ matches ./


  • (.+)/ matches a/b/


  • 1.pdf matches a/b.pdf





share|improve this answer

























  • Very cool. Wish I could regex this well.

    – Brian Fitzpatrick
    May 21 at 5:19











  • Or find . -regex '.*/([^/]*)/1.pdf' and then it would even work with BSD find.

    – Stéphane Chazelas
    May 21 at 8:59



















7














The traditional loop variant of the find .. -exec sh -c '' to use the shell constructs to match the basename and the immediate path above would be to do below.



find foo/ -name '*.pdf' -exec sh -c '
for file; do
base="$file##*/"
path="$file%/*"
if [ "$path##*/" = "$base%.*" ]; then
printf "%sn" "$file"
fi
done' sh +


To breakdown the individual parameter expansions




  • file contains the full path of the .pdf file returned from the find command


  • "$file##*/" contains only the part after the last / i.e. only the basename of the file


  • "$file%/*" contains the path up to the final / i.e. except the basename portion of the result


  • "$path##*/" contains the part after the last / from the path variable, i.e. the immediate folder path above the basename of the file


  • "$base%.*" contains the part of the basename with the .pdf extension removed

So if the basename without extension matches with the name of the immediate folder above, we print the path.






share|improve this answer
































    6














    The reverse of Inian's answer, i.e. look for directories, and then see whether they hold a file with a particular name.



    The following prints the pathnames of the found files relative to the directory foo:



    find foo -type d -exec sh -c '
    for dirpath do
    pathname="$dirpath/$dirpath##*/.pdf"
    if [ -f "$pathname" ]; then
    printf "%sn" "$pathname"
    fi
    done' sh +


    $dirpath##*/ will be replaced by the filename portion of the directory path, and could be replaced by $(basename "$dirpath").



    For people who like the short-circuit syntax:



    find foo -type d -exec sh -c '
    for dirpath do
    pathname="$dirpath/$dirpath##*/.pdf"
    [ -f "$pathname" ] && printf "%sn" "$pathname"
    done' sh +


    The benefit of doing it this way is that you may have more PDF files than directories. The number of tests involved are reduced if one restrict the query by the smaller number (the number of directories).



    For example, if a single directory contains 100 PDF files, this would only try to detect one of them rather than testing the names of all 100 files against that of the directory.






    share|improve this answer
































      3














      with zsh:



      printf '%sn' **/*/*.pdf(e@'[[ $REPLY:t = $REPLY:h:t.pdf ]]'@)


      Beware that while **/ won't follow symlinks, */ will.






      share|improve this answer






























        2














        It was not specified, but here is a solution without regular expressions if anybody is interested.



        We can use find . -type f to just get files, then utilize dirname and basename to write the conditional. The utilities have the following behavior:



        $ find . -type f
        ./dir2/spam/spam.pdf
        ./dir2/dir2.tex
        ./dir3/dir3.pdf
        ./dir3/eggs/eggs.pdf
        ./dir1/dir1.pdf
        ./dir1/dir1.txt


        basename returns just the filename after the last /:



        $ for file in $(find . -type f); do basename $file; done
        spam.pdf
        dir2.tex
        dir3.pdf
        eggs.pdf
        dir1.pdf
        dir1.txt


        dirname gives the entire path up to the final /:



        $ for file in $(find . -type f); do dirname $file; done
        ./dir2/spam
        ./dir2
        ./dir3
        ./dir3/eggs
        ./dir1
        ./dir1


        Therefore, basename $(dirname $file) gives the parent directory of the file.



        $ for file in $(find . -type f); do basename $(dirname $file) ; done
        spam
        dir2
        dir3
        eggs
        dir1
        dir1


        Solution



        Combine the above to form the conditional "$(basename $file)" = "$(basename $(dirname $file))".pdf, then only print each result from find if that conditional returns true.



        $ while read file; do if [ "$(basename "$file")" = "$(basename "$(dirname "$file")")".pdf ]; then echo $file; fi done < <(find . -type f)
        ./dir2/spam/spam.pdf
        ./dir3/dir3.pdf
        ./dir3/eggs/eggs.pdf
        ./dir1/dir1.pdf
        ./Final Thesis/grits/grits.pdf
        ./Final Thesis/Final Thesis.pdf


        In the above example, we've added a directory/file with spaces in the name to treat that case (thanks to @Kusalananda in the comments)






        share|improve this answer

























        • This will unfortunately break on filenames like Final Thesis.pdf (with a space).

          – Kusalananda
          May 21 at 16:17











        • @Kusalananda Fixed.

          – user1717828
          May 21 at 16:38


















        0














        I take bash globbing, simple loop over string tests any day over the Find program. Call me irrational, and while it may well be suboptimal such simple code does the trick for me: readable and reusable, satisfying even!. Allow me therefore to suggest a combination of:



        • bash globstar : for f in ** ; do ...
        ** loops over every files in the current directory and all subfolders.. to check globstar status in your current session: shopt -p globstar. To activate globstar: shopt -s globstar.



        • "file" utlity : if [[ $(file "$f") =~ pdf ]]; then ...
        to check actual file format for pdf - more robust than testing only for the file's extension



        • basename, dirname :
        to compare the file name to the name of the directory immediately above it. basename returns the filename - dirname returns entire directory path - combine the two functions to only return the one directory containing the matching file.
        I put each one in a variable (_mydir and _myf) to then do a simple test using =~ for string matching.



        One subtility: remove any "dot" in the filename to avoid matching filename to current directory whose shortcut is also "." - I used direct string substitution on the variable _myf : $_myf//./ - not very elegant but it works. Positive matches will return each file's path - together with the full path of the current folder by preceding the output with : $(pwd)/.



        Code



        for f in ** ; do
        if [[ $(file "$f") =~ PDF ]]; then
        _mydir="$(basename $(dirname $f))" ;
        _myf="$(basename $f)" ;
        [[ "$_myf//./" =~ "$_mydir" ]] && echo -e "$(pwd)/$f" ;
        fi ;
        done





        share|improve this answer























          Your Answer








          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "106"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f520078%2ffinding-all-files-with-a-given-extension-whose-base-name-is-the-name-of-the-pare%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          6 Answers
          6






          active

          oldest

          votes








          6 Answers
          6






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          16














          With GNU find:



          find . -regextype egrep -regex '.*/([^/]+)/1.pdf'



          • -regextype egrep use egrep style regex.


          • .*/ match grand parent directires.


          • ([^/]+)/ match parent dir in a group.


          • 1.pdf use backreference to match file name as parent dir.

          update



          One (myself for one) might think that .* is greedy enough, it's unnecessary to exclude / from parent matching:



          find . -regextype egrep -regex '.*/(.+)/1.pdf'


          Above command won't work well, because it mathches ./a/b/a/b.pdf:




          • .*/ matches ./


          • (.+)/ matches a/b/


          • 1.pdf matches a/b.pdf





          share|improve this answer

























          • Very cool. Wish I could regex this well.

            – Brian Fitzpatrick
            May 21 at 5:19











          • Or find . -regex '.*/([^/]*)/1.pdf' and then it would even work with BSD find.

            – Stéphane Chazelas
            May 21 at 8:59
















          16














          With GNU find:



          find . -regextype egrep -regex '.*/([^/]+)/1.pdf'



          • -regextype egrep use egrep style regex.


          • .*/ match grand parent directires.


          • ([^/]+)/ match parent dir in a group.


          • 1.pdf use backreference to match file name as parent dir.

          update



          One (myself for one) might think that .* is greedy enough, it's unnecessary to exclude / from parent matching:



          find . -regextype egrep -regex '.*/(.+)/1.pdf'


          Above command won't work well, because it mathches ./a/b/a/b.pdf:




          • .*/ matches ./


          • (.+)/ matches a/b/


          • 1.pdf matches a/b.pdf





          share|improve this answer

























          • Very cool. Wish I could regex this well.

            – Brian Fitzpatrick
            May 21 at 5:19











          • Or find . -regex '.*/([^/]*)/1.pdf' and then it would even work with BSD find.

            – Stéphane Chazelas
            May 21 at 8:59














          16












          16








          16







          With GNU find:



          find . -regextype egrep -regex '.*/([^/]+)/1.pdf'



          • -regextype egrep use egrep style regex.


          • .*/ match grand parent directires.


          • ([^/]+)/ match parent dir in a group.


          • 1.pdf use backreference to match file name as parent dir.

          update



          One (myself for one) might think that .* is greedy enough, it's unnecessary to exclude / from parent matching:



          find . -regextype egrep -regex '.*/(.+)/1.pdf'


          Above command won't work well, because it mathches ./a/b/a/b.pdf:




          • .*/ matches ./


          • (.+)/ matches a/b/


          • 1.pdf matches a/b.pdf





          share|improve this answer















          With GNU find:



          find . -regextype egrep -regex '.*/([^/]+)/1.pdf'



          • -regextype egrep use egrep style regex.


          • .*/ match grand parent directires.


          • ([^/]+)/ match parent dir in a group.


          • 1.pdf use backreference to match file name as parent dir.

          update



          One (myself for one) might think that .* is greedy enough, it's unnecessary to exclude / from parent matching:



          find . -regextype egrep -regex '.*/(.+)/1.pdf'


          Above command won't work well, because it mathches ./a/b/a/b.pdf:




          • .*/ matches ./


          • (.+)/ matches a/b/


          • 1.pdf matches a/b.pdf






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited May 21 at 9:16

























          answered May 21 at 5:16









          dedowsdidedowsdi

          69416




          69416












          • Very cool. Wish I could regex this well.

            – Brian Fitzpatrick
            May 21 at 5:19











          • Or find . -regex '.*/([^/]*)/1.pdf' and then it would even work with BSD find.

            – Stéphane Chazelas
            May 21 at 8:59


















          • Very cool. Wish I could regex this well.

            – Brian Fitzpatrick
            May 21 at 5:19











          • Or find . -regex '.*/([^/]*)/1.pdf' and then it would even work with BSD find.

            – Stéphane Chazelas
            May 21 at 8:59

















          Very cool. Wish I could regex this well.

          – Brian Fitzpatrick
          May 21 at 5:19





          Very cool. Wish I could regex this well.

          – Brian Fitzpatrick
          May 21 at 5:19













          Or find . -regex '.*/([^/]*)/1.pdf' and then it would even work with BSD find.

          – Stéphane Chazelas
          May 21 at 8:59






          Or find . -regex '.*/([^/]*)/1.pdf' and then it would even work with BSD find.

          – Stéphane Chazelas
          May 21 at 8:59














          7














          The traditional loop variant of the find .. -exec sh -c '' to use the shell constructs to match the basename and the immediate path above would be to do below.



          find foo/ -name '*.pdf' -exec sh -c '
          for file; do
          base="$file##*/"
          path="$file%/*"
          if [ "$path##*/" = "$base%.*" ]; then
          printf "%sn" "$file"
          fi
          done' sh +


          To breakdown the individual parameter expansions




          • file contains the full path of the .pdf file returned from the find command


          • "$file##*/" contains only the part after the last / i.e. only the basename of the file


          • "$file%/*" contains the path up to the final / i.e. except the basename portion of the result


          • "$path##*/" contains the part after the last / from the path variable, i.e. the immediate folder path above the basename of the file


          • "$base%.*" contains the part of the basename with the .pdf extension removed

          So if the basename without extension matches with the name of the immediate folder above, we print the path.






          share|improve this answer





























            7














            The traditional loop variant of the find .. -exec sh -c '' to use the shell constructs to match the basename and the immediate path above would be to do below.



            find foo/ -name '*.pdf' -exec sh -c '
            for file; do
            base="$file##*/"
            path="$file%/*"
            if [ "$path##*/" = "$base%.*" ]; then
            printf "%sn" "$file"
            fi
            done' sh +


            To breakdown the individual parameter expansions




            • file contains the full path of the .pdf file returned from the find command


            • "$file##*/" contains only the part after the last / i.e. only the basename of the file


            • "$file%/*" contains the path up to the final / i.e. except the basename portion of the result


            • "$path##*/" contains the part after the last / from the path variable, i.e. the immediate folder path above the basename of the file


            • "$base%.*" contains the part of the basename with the .pdf extension removed

            So if the basename without extension matches with the name of the immediate folder above, we print the path.






            share|improve this answer



























              7












              7








              7







              The traditional loop variant of the find .. -exec sh -c '' to use the shell constructs to match the basename and the immediate path above would be to do below.



              find foo/ -name '*.pdf' -exec sh -c '
              for file; do
              base="$file##*/"
              path="$file%/*"
              if [ "$path##*/" = "$base%.*" ]; then
              printf "%sn" "$file"
              fi
              done' sh +


              To breakdown the individual parameter expansions




              • file contains the full path of the .pdf file returned from the find command


              • "$file##*/" contains only the part after the last / i.e. only the basename of the file


              • "$file%/*" contains the path up to the final / i.e. except the basename portion of the result


              • "$path##*/" contains the part after the last / from the path variable, i.e. the immediate folder path above the basename of the file


              • "$base%.*" contains the part of the basename with the .pdf extension removed

              So if the basename without extension matches with the name of the immediate folder above, we print the path.






              share|improve this answer















              The traditional loop variant of the find .. -exec sh -c '' to use the shell constructs to match the basename and the immediate path above would be to do below.



              find foo/ -name '*.pdf' -exec sh -c '
              for file; do
              base="$file##*/"
              path="$file%/*"
              if [ "$path##*/" = "$base%.*" ]; then
              printf "%sn" "$file"
              fi
              done' sh +


              To breakdown the individual parameter expansions




              • file contains the full path of the .pdf file returned from the find command


              • "$file##*/" contains only the part after the last / i.e. only the basename of the file


              • "$file%/*" contains the path up to the final / i.e. except the basename portion of the result


              • "$path##*/" contains the part after the last / from the path variable, i.e. the immediate folder path above the basename of the file


              • "$base%.*" contains the part of the basename with the .pdf extension removed

              So if the basename without extension matches with the name of the immediate folder above, we print the path.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited May 21 at 5:55

























              answered May 21 at 5:49









              InianInian

              6,0751633




              6,0751633





















                  6














                  The reverse of Inian's answer, i.e. look for directories, and then see whether they hold a file with a particular name.



                  The following prints the pathnames of the found files relative to the directory foo:



                  find foo -type d -exec sh -c '
                  for dirpath do
                  pathname="$dirpath/$dirpath##*/.pdf"
                  if [ -f "$pathname" ]; then
                  printf "%sn" "$pathname"
                  fi
                  done' sh +


                  $dirpath##*/ will be replaced by the filename portion of the directory path, and could be replaced by $(basename "$dirpath").



                  For people who like the short-circuit syntax:



                  find foo -type d -exec sh -c '
                  for dirpath do
                  pathname="$dirpath/$dirpath##*/.pdf"
                  [ -f "$pathname" ] && printf "%sn" "$pathname"
                  done' sh +


                  The benefit of doing it this way is that you may have more PDF files than directories. The number of tests involved are reduced if one restrict the query by the smaller number (the number of directories).



                  For example, if a single directory contains 100 PDF files, this would only try to detect one of them rather than testing the names of all 100 files against that of the directory.






                  share|improve this answer





























                    6














                    The reverse of Inian's answer, i.e. look for directories, and then see whether they hold a file with a particular name.



                    The following prints the pathnames of the found files relative to the directory foo:



                    find foo -type d -exec sh -c '
                    for dirpath do
                    pathname="$dirpath/$dirpath##*/.pdf"
                    if [ -f "$pathname" ]; then
                    printf "%sn" "$pathname"
                    fi
                    done' sh +


                    $dirpath##*/ will be replaced by the filename portion of the directory path, and could be replaced by $(basename "$dirpath").



                    For people who like the short-circuit syntax:



                    find foo -type d -exec sh -c '
                    for dirpath do
                    pathname="$dirpath/$dirpath##*/.pdf"
                    [ -f "$pathname" ] && printf "%sn" "$pathname"
                    done' sh +


                    The benefit of doing it this way is that you may have more PDF files than directories. The number of tests involved are reduced if one restrict the query by the smaller number (the number of directories).



                    For example, if a single directory contains 100 PDF files, this would only try to detect one of them rather than testing the names of all 100 files against that of the directory.






                    share|improve this answer



























                      6












                      6








                      6







                      The reverse of Inian's answer, i.e. look for directories, and then see whether they hold a file with a particular name.



                      The following prints the pathnames of the found files relative to the directory foo:



                      find foo -type d -exec sh -c '
                      for dirpath do
                      pathname="$dirpath/$dirpath##*/.pdf"
                      if [ -f "$pathname" ]; then
                      printf "%sn" "$pathname"
                      fi
                      done' sh +


                      $dirpath##*/ will be replaced by the filename portion of the directory path, and could be replaced by $(basename "$dirpath").



                      For people who like the short-circuit syntax:



                      find foo -type d -exec sh -c '
                      for dirpath do
                      pathname="$dirpath/$dirpath##*/.pdf"
                      [ -f "$pathname" ] && printf "%sn" "$pathname"
                      done' sh +


                      The benefit of doing it this way is that you may have more PDF files than directories. The number of tests involved are reduced if one restrict the query by the smaller number (the number of directories).



                      For example, if a single directory contains 100 PDF files, this would only try to detect one of them rather than testing the names of all 100 files against that of the directory.






                      share|improve this answer















                      The reverse of Inian's answer, i.e. look for directories, and then see whether they hold a file with a particular name.



                      The following prints the pathnames of the found files relative to the directory foo:



                      find foo -type d -exec sh -c '
                      for dirpath do
                      pathname="$dirpath/$dirpath##*/.pdf"
                      if [ -f "$pathname" ]; then
                      printf "%sn" "$pathname"
                      fi
                      done' sh +


                      $dirpath##*/ will be replaced by the filename portion of the directory path, and could be replaced by $(basename "$dirpath").



                      For people who like the short-circuit syntax:



                      find foo -type d -exec sh -c '
                      for dirpath do
                      pathname="$dirpath/$dirpath##*/.pdf"
                      [ -f "$pathname" ] && printf "%sn" "$pathname"
                      done' sh +


                      The benefit of doing it this way is that you may have more PDF files than directories. The number of tests involved are reduced if one restrict the query by the smaller number (the number of directories).



                      For example, if a single directory contains 100 PDF files, this would only try to detect one of them rather than testing the names of all 100 files against that of the directory.







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited May 21 at 15:40

























                      answered May 21 at 6:58









                      KusalanandaKusalananda

                      148k18279466




                      148k18279466





















                          3














                          with zsh:



                          printf '%sn' **/*/*.pdf(e@'[[ $REPLY:t = $REPLY:h:t.pdf ]]'@)


                          Beware that while **/ won't follow symlinks, */ will.






                          share|improve this answer



























                            3














                            with zsh:



                            printf '%sn' **/*/*.pdf(e@'[[ $REPLY:t = $REPLY:h:t.pdf ]]'@)


                            Beware that while **/ won't follow symlinks, */ will.






                            share|improve this answer

























                              3












                              3








                              3







                              with zsh:



                              printf '%sn' **/*/*.pdf(e@'[[ $REPLY:t = $REPLY:h:t.pdf ]]'@)


                              Beware that while **/ won't follow symlinks, */ will.






                              share|improve this answer













                              with zsh:



                              printf '%sn' **/*/*.pdf(e@'[[ $REPLY:t = $REPLY:h:t.pdf ]]'@)


                              Beware that while **/ won't follow symlinks, */ will.







                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered May 21 at 5:59









                              Stéphane ChazelasStéphane Chazelas

                              320k57606975




                              320k57606975





















                                  2














                                  It was not specified, but here is a solution without regular expressions if anybody is interested.



                                  We can use find . -type f to just get files, then utilize dirname and basename to write the conditional. The utilities have the following behavior:



                                  $ find . -type f
                                  ./dir2/spam/spam.pdf
                                  ./dir2/dir2.tex
                                  ./dir3/dir3.pdf
                                  ./dir3/eggs/eggs.pdf
                                  ./dir1/dir1.pdf
                                  ./dir1/dir1.txt


                                  basename returns just the filename after the last /:



                                  $ for file in $(find . -type f); do basename $file; done
                                  spam.pdf
                                  dir2.tex
                                  dir3.pdf
                                  eggs.pdf
                                  dir1.pdf
                                  dir1.txt


                                  dirname gives the entire path up to the final /:



                                  $ for file in $(find . -type f); do dirname $file; done
                                  ./dir2/spam
                                  ./dir2
                                  ./dir3
                                  ./dir3/eggs
                                  ./dir1
                                  ./dir1


                                  Therefore, basename $(dirname $file) gives the parent directory of the file.



                                  $ for file in $(find . -type f); do basename $(dirname $file) ; done
                                  spam
                                  dir2
                                  dir3
                                  eggs
                                  dir1
                                  dir1


                                  Solution



                                  Combine the above to form the conditional "$(basename $file)" = "$(basename $(dirname $file))".pdf, then only print each result from find if that conditional returns true.



                                  $ while read file; do if [ "$(basename "$file")" = "$(basename "$(dirname "$file")")".pdf ]; then echo $file; fi done < <(find . -type f)
                                  ./dir2/spam/spam.pdf
                                  ./dir3/dir3.pdf
                                  ./dir3/eggs/eggs.pdf
                                  ./dir1/dir1.pdf
                                  ./Final Thesis/grits/grits.pdf
                                  ./Final Thesis/Final Thesis.pdf


                                  In the above example, we've added a directory/file with spaces in the name to treat that case (thanks to @Kusalananda in the comments)






                                  share|improve this answer

























                                  • This will unfortunately break on filenames like Final Thesis.pdf (with a space).

                                    – Kusalananda
                                    May 21 at 16:17











                                  • @Kusalananda Fixed.

                                    – user1717828
                                    May 21 at 16:38















                                  2














                                  It was not specified, but here is a solution without regular expressions if anybody is interested.



                                  We can use find . -type f to just get files, then utilize dirname and basename to write the conditional. The utilities have the following behavior:



                                  $ find . -type f
                                  ./dir2/spam/spam.pdf
                                  ./dir2/dir2.tex
                                  ./dir3/dir3.pdf
                                  ./dir3/eggs/eggs.pdf
                                  ./dir1/dir1.pdf
                                  ./dir1/dir1.txt


                                  basename returns just the filename after the last /:



                                  $ for file in $(find . -type f); do basename $file; done
                                  spam.pdf
                                  dir2.tex
                                  dir3.pdf
                                  eggs.pdf
                                  dir1.pdf
                                  dir1.txt


                                  dirname gives the entire path up to the final /:



                                  $ for file in $(find . -type f); do dirname $file; done
                                  ./dir2/spam
                                  ./dir2
                                  ./dir3
                                  ./dir3/eggs
                                  ./dir1
                                  ./dir1


                                  Therefore, basename $(dirname $file) gives the parent directory of the file.



                                  $ for file in $(find . -type f); do basename $(dirname $file) ; done
                                  spam
                                  dir2
                                  dir3
                                  eggs
                                  dir1
                                  dir1


                                  Solution



                                  Combine the above to form the conditional "$(basename $file)" = "$(basename $(dirname $file))".pdf, then only print each result from find if that conditional returns true.



                                  $ while read file; do if [ "$(basename "$file")" = "$(basename "$(dirname "$file")")".pdf ]; then echo $file; fi done < <(find . -type f)
                                  ./dir2/spam/spam.pdf
                                  ./dir3/dir3.pdf
                                  ./dir3/eggs/eggs.pdf
                                  ./dir1/dir1.pdf
                                  ./Final Thesis/grits/grits.pdf
                                  ./Final Thesis/Final Thesis.pdf


                                  In the above example, we've added a directory/file with spaces in the name to treat that case (thanks to @Kusalananda in the comments)






                                  share|improve this answer

























                                  • This will unfortunately break on filenames like Final Thesis.pdf (with a space).

                                    – Kusalananda
                                    May 21 at 16:17











                                  • @Kusalananda Fixed.

                                    – user1717828
                                    May 21 at 16:38













                                  2












                                  2








                                  2







                                  It was not specified, but here is a solution without regular expressions if anybody is interested.



                                  We can use find . -type f to just get files, then utilize dirname and basename to write the conditional. The utilities have the following behavior:



                                  $ find . -type f
                                  ./dir2/spam/spam.pdf
                                  ./dir2/dir2.tex
                                  ./dir3/dir3.pdf
                                  ./dir3/eggs/eggs.pdf
                                  ./dir1/dir1.pdf
                                  ./dir1/dir1.txt


                                  basename returns just the filename after the last /:



                                  $ for file in $(find . -type f); do basename $file; done
                                  spam.pdf
                                  dir2.tex
                                  dir3.pdf
                                  eggs.pdf
                                  dir1.pdf
                                  dir1.txt


                                  dirname gives the entire path up to the final /:



                                  $ for file in $(find . -type f); do dirname $file; done
                                  ./dir2/spam
                                  ./dir2
                                  ./dir3
                                  ./dir3/eggs
                                  ./dir1
                                  ./dir1


                                  Therefore, basename $(dirname $file) gives the parent directory of the file.



                                  $ for file in $(find . -type f); do basename $(dirname $file) ; done
                                  spam
                                  dir2
                                  dir3
                                  eggs
                                  dir1
                                  dir1


                                  Solution



                                  Combine the above to form the conditional "$(basename $file)" = "$(basename $(dirname $file))".pdf, then only print each result from find if that conditional returns true.



                                  $ while read file; do if [ "$(basename "$file")" = "$(basename "$(dirname "$file")")".pdf ]; then echo $file; fi done < <(find . -type f)
                                  ./dir2/spam/spam.pdf
                                  ./dir3/dir3.pdf
                                  ./dir3/eggs/eggs.pdf
                                  ./dir1/dir1.pdf
                                  ./Final Thesis/grits/grits.pdf
                                  ./Final Thesis/Final Thesis.pdf


                                  In the above example, we've added a directory/file with spaces in the name to treat that case (thanks to @Kusalananda in the comments)






                                  share|improve this answer















                                  It was not specified, but here is a solution without regular expressions if anybody is interested.



                                  We can use find . -type f to just get files, then utilize dirname and basename to write the conditional. The utilities have the following behavior:



                                  $ find . -type f
                                  ./dir2/spam/spam.pdf
                                  ./dir2/dir2.tex
                                  ./dir3/dir3.pdf
                                  ./dir3/eggs/eggs.pdf
                                  ./dir1/dir1.pdf
                                  ./dir1/dir1.txt


                                  basename returns just the filename after the last /:



                                  $ for file in $(find . -type f); do basename $file; done
                                  spam.pdf
                                  dir2.tex
                                  dir3.pdf
                                  eggs.pdf
                                  dir1.pdf
                                  dir1.txt


                                  dirname gives the entire path up to the final /:



                                  $ for file in $(find . -type f); do dirname $file; done
                                  ./dir2/spam
                                  ./dir2
                                  ./dir3
                                  ./dir3/eggs
                                  ./dir1
                                  ./dir1


                                  Therefore, basename $(dirname $file) gives the parent directory of the file.



                                  $ for file in $(find . -type f); do basename $(dirname $file) ; done
                                  spam
                                  dir2
                                  dir3
                                  eggs
                                  dir1
                                  dir1


                                  Solution



                                  Combine the above to form the conditional "$(basename $file)" = "$(basename $(dirname $file))".pdf, then only print each result from find if that conditional returns true.



                                  $ while read file; do if [ "$(basename "$file")" = "$(basename "$(dirname "$file")")".pdf ]; then echo $file; fi done < <(find . -type f)
                                  ./dir2/spam/spam.pdf
                                  ./dir3/dir3.pdf
                                  ./dir3/eggs/eggs.pdf
                                  ./dir1/dir1.pdf
                                  ./Final Thesis/grits/grits.pdf
                                  ./Final Thesis/Final Thesis.pdf


                                  In the above example, we've added a directory/file with spaces in the name to treat that case (thanks to @Kusalananda in the comments)







                                  share|improve this answer














                                  share|improve this answer



                                  share|improve this answer








                                  edited May 21 at 16:37

























                                  answered May 21 at 15:58









                                  user1717828user1717828

                                  1,75531427




                                  1,75531427












                                  • This will unfortunately break on filenames like Final Thesis.pdf (with a space).

                                    – Kusalananda
                                    May 21 at 16:17











                                  • @Kusalananda Fixed.

                                    – user1717828
                                    May 21 at 16:38

















                                  • This will unfortunately break on filenames like Final Thesis.pdf (with a space).

                                    – Kusalananda
                                    May 21 at 16:17











                                  • @Kusalananda Fixed.

                                    – user1717828
                                    May 21 at 16:38
















                                  This will unfortunately break on filenames like Final Thesis.pdf (with a space).

                                  – Kusalananda
                                  May 21 at 16:17





                                  This will unfortunately break on filenames like Final Thesis.pdf (with a space).

                                  – Kusalananda
                                  May 21 at 16:17













                                  @Kusalananda Fixed.

                                  – user1717828
                                  May 21 at 16:38





                                  @Kusalananda Fixed.

                                  – user1717828
                                  May 21 at 16:38











                                  0














                                  I take bash globbing, simple loop over string tests any day over the Find program. Call me irrational, and while it may well be suboptimal such simple code does the trick for me: readable and reusable, satisfying even!. Allow me therefore to suggest a combination of:



                                  • bash globstar : for f in ** ; do ...
                                  ** loops over every files in the current directory and all subfolders.. to check globstar status in your current session: shopt -p globstar. To activate globstar: shopt -s globstar.



                                  • "file" utlity : if [[ $(file "$f") =~ pdf ]]; then ...
                                  to check actual file format for pdf - more robust than testing only for the file's extension



                                  • basename, dirname :
                                  to compare the file name to the name of the directory immediately above it. basename returns the filename - dirname returns entire directory path - combine the two functions to only return the one directory containing the matching file.
                                  I put each one in a variable (_mydir and _myf) to then do a simple test using =~ for string matching.



                                  One subtility: remove any "dot" in the filename to avoid matching filename to current directory whose shortcut is also "." - I used direct string substitution on the variable _myf : $_myf//./ - not very elegant but it works. Positive matches will return each file's path - together with the full path of the current folder by preceding the output with : $(pwd)/.



                                  Code



                                  for f in ** ; do
                                  if [[ $(file "$f") =~ PDF ]]; then
                                  _mydir="$(basename $(dirname $f))" ;
                                  _myf="$(basename $f)" ;
                                  [[ "$_myf//./" =~ "$_mydir" ]] && echo -e "$(pwd)/$f" ;
                                  fi ;
                                  done





                                  share|improve this answer



























                                    0














                                    I take bash globbing, simple loop over string tests any day over the Find program. Call me irrational, and while it may well be suboptimal such simple code does the trick for me: readable and reusable, satisfying even!. Allow me therefore to suggest a combination of:



                                    • bash globstar : for f in ** ; do ...
                                    ** loops over every files in the current directory and all subfolders.. to check globstar status in your current session: shopt -p globstar. To activate globstar: shopt -s globstar.



                                    • "file" utlity : if [[ $(file "$f") =~ pdf ]]; then ...
                                    to check actual file format for pdf - more robust than testing only for the file's extension



                                    • basename, dirname :
                                    to compare the file name to the name of the directory immediately above it. basename returns the filename - dirname returns entire directory path - combine the two functions to only return the one directory containing the matching file.
                                    I put each one in a variable (_mydir and _myf) to then do a simple test using =~ for string matching.



                                    One subtility: remove any "dot" in the filename to avoid matching filename to current directory whose shortcut is also "." - I used direct string substitution on the variable _myf : $_myf//./ - not very elegant but it works. Positive matches will return each file's path - together with the full path of the current folder by preceding the output with : $(pwd)/.



                                    Code



                                    for f in ** ; do
                                    if [[ $(file "$f") =~ PDF ]]; then
                                    _mydir="$(basename $(dirname $f))" ;
                                    _myf="$(basename $f)" ;
                                    [[ "$_myf//./" =~ "$_mydir" ]] && echo -e "$(pwd)/$f" ;
                                    fi ;
                                    done





                                    share|improve this answer

























                                      0












                                      0








                                      0







                                      I take bash globbing, simple loop over string tests any day over the Find program. Call me irrational, and while it may well be suboptimal such simple code does the trick for me: readable and reusable, satisfying even!. Allow me therefore to suggest a combination of:



                                      • bash globstar : for f in ** ; do ...
                                      ** loops over every files in the current directory and all subfolders.. to check globstar status in your current session: shopt -p globstar. To activate globstar: shopt -s globstar.



                                      • "file" utlity : if [[ $(file "$f") =~ pdf ]]; then ...
                                      to check actual file format for pdf - more robust than testing only for the file's extension



                                      • basename, dirname :
                                      to compare the file name to the name of the directory immediately above it. basename returns the filename - dirname returns entire directory path - combine the two functions to only return the one directory containing the matching file.
                                      I put each one in a variable (_mydir and _myf) to then do a simple test using =~ for string matching.



                                      One subtility: remove any "dot" in the filename to avoid matching filename to current directory whose shortcut is also "." - I used direct string substitution on the variable _myf : $_myf//./ - not very elegant but it works. Positive matches will return each file's path - together with the full path of the current folder by preceding the output with : $(pwd)/.



                                      Code



                                      for f in ** ; do
                                      if [[ $(file "$f") =~ PDF ]]; then
                                      _mydir="$(basename $(dirname $f))" ;
                                      _myf="$(basename $f)" ;
                                      [[ "$_myf//./" =~ "$_mydir" ]] && echo -e "$(pwd)/$f" ;
                                      fi ;
                                      done





                                      share|improve this answer













                                      I take bash globbing, simple loop over string tests any day over the Find program. Call me irrational, and while it may well be suboptimal such simple code does the trick for me: readable and reusable, satisfying even!. Allow me therefore to suggest a combination of:



                                      • bash globstar : for f in ** ; do ...
                                      ** loops over every files in the current directory and all subfolders.. to check globstar status in your current session: shopt -p globstar. To activate globstar: shopt -s globstar.



                                      • "file" utlity : if [[ $(file "$f") =~ pdf ]]; then ...
                                      to check actual file format for pdf - more robust than testing only for the file's extension



                                      • basename, dirname :
                                      to compare the file name to the name of the directory immediately above it. basename returns the filename - dirname returns entire directory path - combine the two functions to only return the one directory containing the matching file.
                                      I put each one in a variable (_mydir and _myf) to then do a simple test using =~ for string matching.



                                      One subtility: remove any "dot" in the filename to avoid matching filename to current directory whose shortcut is also "." - I used direct string substitution on the variable _myf : $_myf//./ - not very elegant but it works. Positive matches will return each file's path - together with the full path of the current folder by preceding the output with : $(pwd)/.



                                      Code



                                      for f in ** ; do
                                      if [[ $(file "$f") =~ PDF ]]; then
                                      _mydir="$(basename $(dirname $f))" ;
                                      _myf="$(basename $f)" ;
                                      [[ "$_myf//./" =~ "$_mydir" ]] && echo -e "$(pwd)/$f" ;
                                      fi ;
                                      done






                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered May 24 at 2:34









                                      docgyneco69docgyneco69

                                      6113




                                      6113



























                                          draft saved

                                          draft discarded
















































                                          Thanks for contributing an answer to Unix & Linux Stack Exchange!


                                          • Please be sure to answer the question. Provide details and share your research!

                                          But avoid


                                          • Asking for help, clarification, or responding to other answers.

                                          • Making statements based on opinion; back them up with references or personal experience.

                                          To learn more, see our tips on writing great answers.




                                          draft saved


                                          draft discarded














                                          StackExchange.ready(
                                          function ()
                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f520078%2ffinding-all-files-with-a-given-extension-whose-base-name-is-the-name-of-the-pare%23new-answer', 'question_page');

                                          );

                                          Post as a guest















                                          Required, but never shown





















































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown

































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown







                                          sLXfS2Nagp6DVDMPTdzETGjZ5IVxoEZlt2 Z gkQh1DshBZSfk8Lxy3Vzue9Qq6KKOgbnjNpXfPwAp2HEfl1eIx3Gn5VaiA
                                          B8xmLFJd 3M79scv,sVtcTSOgpfB0DzpB27 xsp IN5Pcd5ai48STm7Sy4m8JhEy7XuxQozJNT5CSVK3D

                                          Popular posts from this blog

                                          Category:9 (number) SubcategoriesMedia in category "9 (number)"Navigation menuUpload mediaGND ID: 4485639-8Library of Congress authority ID: sh85091979ReasonatorScholiaStatistics

                                          Circuit construction for execution of conditional statements using least significant bitHow are two different registers being used as “control”?How exactly is the stated composite state of the two registers being produced using the $R_zz$ controlled rotations?Efficiently performing controlled rotations in HHLWould this quantum algorithm implementation work?How to prepare a superposed states of odd integers from $1$ to $sqrtN$?Why is this implementation of the order finding algorithm not working?Circuit construction for Hamiltonian simulationHow can I invert the least significant bit of a certain term of a superposed state?Implementing an oracleImplementing a controlled sum operation

                                          Magento 2 “No Payment Methods” in Admin New OrderHow to integrate Paypal Express Checkout with the Magento APIMagento 1.5 - Sales > Order > edit order and shipping methods disappearAuto Invoice Check/Money Order Payment methodAdd more simple payment methods?Shipping methods not showingWhat should I do to change payment methods if changing the configuration has no effects?1.9 - No Payment Methods showing upMy Payment Methods not Showing for downloadable/virtual product when checkout?Magento2 API to access internal payment methodHow to call an existing payment methods in the registration form?