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

What was with Miles Morales's stickers?

What can plausibly explain many of my very long and low-tech bridges?

What language is the software written in on the ISS?

Arriving at the same result with the opposite hypotheses

Can a user sell my software (MIT license) without modification?

Russian equivalents of "no love lost"

Is this a mistake? (regarding maximum likelihood estimator)

What's up with this leaf?

Should an arbiter claim draw at a K+R vs K+R endgame?

What's the name of this light airplane?

My coworkers think I had a long honeymoon. Actually I was diagnosed with cancer. How do I talk about it?

Using "subway" as name for London Underground?

Can an Aarakocra use a shield while flying?

Taxi Services at Didcot

Movie about a boy who was born old and grew young

How did they achieve the Gunslinger's shining eye effect in Westworld?

What is the giant octopus in the torture chamber for?

Find the Factorial From the Given Prime Relationship

What does the "c." listed under weapon length mean?

Is open-sourcing the code of a webapp not recommended?

PhD - Well known professor or well known school?

Can the poison from Kingsmen be concocted?

Is it possible to 'live off the sea'

Hottest Possible Hydrogen-Fusing Stars



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
































    7














    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

          70416




          70416












          • 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,2901734




              6,2901734





















                  7














                  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





























                    7














                    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



























                      7












                      7








                      7







                      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

                      149k18283471




                      149k18283471





















                          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

                              320k57612981




                              320k57612981





















                                  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







                                          Popular posts from this blog

                                          Wikipedia:Vital articles Мазмуну Biography - Өмүр баян Philosophy and psychology - Философия жана психология Religion - Дин Social sciences - Коомдук илимдер Language and literature - Тил жана адабият Science - Илим Technology - Технология Arts and recreation - Искусство жана эс алуу History and geography - Тарых жана география Навигация менюсу

                                          Bruxelas-Capital Índice Historia | Composición | Situación lingüística | Clima | Cidades irmandadas | Notas | Véxase tamén | Menú de navegacióneO uso das linguas en Bruxelas e a situación do neerlandés"Rexión de Bruxelas Capital"o orixinalSitio da rexiónPáxina de Bruselas no sitio da Oficina de Promoción Turística de Valonia e BruxelasMapa Interactivo da Rexión de Bruxelas-CapitaleeWorldCat332144929079854441105155190212ID28008674080552-90000 0001 0666 3698n94104302ID540940339365017018237

                                          What should I write in an apology letter, since I have decided not to join a company after accepting an offer letterShould I keep looking after accepting a job offer?What should I do when I've been verbally told I would get an offer letter, but still haven't gotten one after 4 weeks?Do I accept an offer from a company that I am not likely to join?New job hasn't confirmed starting date and I want to give current employer as much notice as possibleHow should I address my manager in my resignation letter?HR delayed background verification, now jobless as resignedNo email communication after accepting a formal written offer. How should I phrase the call?What should I do if after receiving a verbal offer letter I am informed that my written job offer is put on hold due to some internal issues?Should I inform the current employer that I am about to resign within 1-2 weeks since I have signed the offer letter and waiting for visa?What company will do, if I send their offer letter to another company