bash command to create array with the 10 most recent images in a dir? Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern) 2019 Community Moderator Election Results Why I closed the “Why is Kali so hard” questionSplit shell horizontally to show ls -al and pwdFinding all “Non-Binary” filesFinding all kinds of extensions referenced in a html fileHow to do more than one substring replace at once in bash?Create array in bash with variables as array nameDynamically create array in bash with variables as array namebash array with variable in the nameHow can I find files with a long first line?find modified files recursively and copy with directory preserving directory structureCreate new array with unique values from existing arrayHow to rsync chronologically starting with the most recent files

Is "Reachable Object" really an NP-complete problem?

Closed form of recurrent arithmetic series summation

Maximum summed powersets with non-adjacent items

When a candle burns, why does the top of wick glow if bottom of flame is hottest?

Is there such thing as an Availability Group failover trigger?

Has negative voting ever been officially implemented in elections, or seriously proposed, or even studied?

What are the out-of-universe reasons for the references to Toby Maguire-era Spider-Man in ITSV

An adverb for when you're not exaggerating

また usage in a dictionary

How do I find out the mythology and history of my Fortress?

What does this Jacques Hadamard quote mean?

What does "lightly crushed" mean for cardamon pods?

Using et al. for a last / senior author rather than for a first author

Is it fair for a professor to grade us on the possession of past papers?

Amount of permutations on an NxNxN Rubik's Cube

Fundamental Solution of the Pell Equation

Would "destroying" Wurmcoil Engine prevent its tokens from being created?

Why wasn't DOSKEY integrated with COMMAND.COM?

What is homebrew?

Why do we bend a book to keep it straight?

Do wooden building fires get hotter than 600°C?

Delete nth line from bottom

Denied boarding although I have proper visa and documentation. To whom should I make a complaint?

Is it a good idea to use CNN to classify 1D signal?



bash command to create array with the 10 most recent images in a dir?



Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)
2019 Community Moderator Election Results
Why I closed the “Why is Kali so hard” questionSplit shell horizontally to show ls -al and pwdFinding all “Non-Binary” filesFinding all kinds of extensions referenced in a html fileHow to do more than one substring replace at once in bash?Create array in bash with variables as array nameDynamically create array in bash with variables as array namebash array with variable in the nameHow can I find files with a long first line?find modified files recursively and copy with directory preserving directory structureCreate new array with unique values from existing arrayHow to rsync chronologically starting with the most recent files



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








3















I'm writing a bash script and I need to create an array with the 10 most recent image files (from new to old) in the current dir.



I consider "image files" to be files with certain extensions, like .jpg or .png. I only require a few specific image types to be supported, I can also express this in one regex like ".(jpg|png)$".



My problem is, if I try to do this with e.g. $list=(ls -1t *.jpg *.png | head -10) the resulting list of files somehow becomes one element, instead of each filename being a separate element in my array.



If I try to use $list=(find -E . -iregex ".*(jpg|png)" -maxdepth 1 -type f | head -10), I'm not sure how to sort the list on date/time and keep only the filenames. Also find seems to put ./ in front of every file but I can get rid of that with sed. And also with find I still have the problem of my entire list becoming one entry in the $list array.










share|improve this question






















  • Is bash a hard requirement, or is a zsh solution acceptable?

    – Jeff Schaller
    2 days ago











  • I was actually hoping to use this on Linux (which I guess has bash 4 and zsh) as well as macOs (which only has bash 3, I think).

    – RocketNuts
    15 hours ago











  • I see evidence of others on OSX with zsh; is that still an option, or no?

    – Jeff Schaller
    15 hours ago











  • @JeffSchaller In that case, sure!

    – RocketNuts
    15 hours ago


















3















I'm writing a bash script and I need to create an array with the 10 most recent image files (from new to old) in the current dir.



I consider "image files" to be files with certain extensions, like .jpg or .png. I only require a few specific image types to be supported, I can also express this in one regex like ".(jpg|png)$".



My problem is, if I try to do this with e.g. $list=(ls -1t *.jpg *.png | head -10) the resulting list of files somehow becomes one element, instead of each filename being a separate element in my array.



If I try to use $list=(find -E . -iregex ".*(jpg|png)" -maxdepth 1 -type f | head -10), I'm not sure how to sort the list on date/time and keep only the filenames. Also find seems to put ./ in front of every file but I can get rid of that with sed. And also with find I still have the problem of my entire list becoming one entry in the $list array.










share|improve this question






















  • Is bash a hard requirement, or is a zsh solution acceptable?

    – Jeff Schaller
    2 days ago











  • I was actually hoping to use this on Linux (which I guess has bash 4 and zsh) as well as macOs (which only has bash 3, I think).

    – RocketNuts
    15 hours ago











  • I see evidence of others on OSX with zsh; is that still an option, or no?

    – Jeff Schaller
    15 hours ago











  • @JeffSchaller In that case, sure!

    – RocketNuts
    15 hours ago














3












3








3


1






I'm writing a bash script and I need to create an array with the 10 most recent image files (from new to old) in the current dir.



I consider "image files" to be files with certain extensions, like .jpg or .png. I only require a few specific image types to be supported, I can also express this in one regex like ".(jpg|png)$".



My problem is, if I try to do this with e.g. $list=(ls -1t *.jpg *.png | head -10) the resulting list of files somehow becomes one element, instead of each filename being a separate element in my array.



If I try to use $list=(find -E . -iregex ".*(jpg|png)" -maxdepth 1 -type f | head -10), I'm not sure how to sort the list on date/time and keep only the filenames. Also find seems to put ./ in front of every file but I can get rid of that with sed. And also with find I still have the problem of my entire list becoming one entry in the $list array.










share|improve this question














I'm writing a bash script and I need to create an array with the 10 most recent image files (from new to old) in the current dir.



I consider "image files" to be files with certain extensions, like .jpg or .png. I only require a few specific image types to be supported, I can also express this in one regex like ".(jpg|png)$".



My problem is, if I try to do this with e.g. $list=(ls -1t *.jpg *.png | head -10) the resulting list of files somehow becomes one element, instead of each filename being a separate element in my array.



If I try to use $list=(find -E . -iregex ".*(jpg|png)" -maxdepth 1 -type f | head -10), I'm not sure how to sort the list on date/time and keep only the filenames. Also find seems to put ./ in front of every file but I can get rid of that with sed. And also with find I still have the problem of my entire list becoming one entry in the $list array.







bash find sort array file-search






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 2 days ago









RocketNutsRocketNuts

138115




138115












  • Is bash a hard requirement, or is a zsh solution acceptable?

    – Jeff Schaller
    2 days ago











  • I was actually hoping to use this on Linux (which I guess has bash 4 and zsh) as well as macOs (which only has bash 3, I think).

    – RocketNuts
    15 hours ago











  • I see evidence of others on OSX with zsh; is that still an option, or no?

    – Jeff Schaller
    15 hours ago











  • @JeffSchaller In that case, sure!

    – RocketNuts
    15 hours ago


















  • Is bash a hard requirement, or is a zsh solution acceptable?

    – Jeff Schaller
    2 days ago











  • I was actually hoping to use this on Linux (which I guess has bash 4 and zsh) as well as macOs (which only has bash 3, I think).

    – RocketNuts
    15 hours ago











  • I see evidence of others on OSX with zsh; is that still an option, or no?

    – Jeff Schaller
    15 hours ago











  • @JeffSchaller In that case, sure!

    – RocketNuts
    15 hours ago

















Is bash a hard requirement, or is a zsh solution acceptable?

– Jeff Schaller
2 days ago





Is bash a hard requirement, or is a zsh solution acceptable?

– Jeff Schaller
2 days ago













I was actually hoping to use this on Linux (which I guess has bash 4 and zsh) as well as macOs (which only has bash 3, I think).

– RocketNuts
15 hours ago





I was actually hoping to use this on Linux (which I guess has bash 4 and zsh) as well as macOs (which only has bash 3, I think).

– RocketNuts
15 hours ago













I see evidence of others on OSX with zsh; is that still an option, or no?

– Jeff Schaller
15 hours ago





I see evidence of others on OSX with zsh; is that still an option, or no?

– Jeff Schaller
15 hours ago













@JeffSchaller In that case, sure!

– RocketNuts
15 hours ago






@JeffSchaller In that case, sure!

– RocketNuts
15 hours ago











3 Answers
3






active

oldest

votes


















4














The correct syntax is:



list=($(ls -t *.jpg *.png | head -10))
echo First element: $list[0]
echo Last element: $list[9]


However, this solution will have problems with file names containing space characters (or any white space in general).






share|improve this answer










New contributor




FedonKadifeli is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




















  • Thanks, I assume I can overcome the whitespace issue by doing something like IFS=$(echo -en "nb") first?

    – RocketNuts
    15 hours ago


















2














For bash ≥ 4:



To read output of a command into an array line by line, you should use readarray:



readarray files < <(ls -1t *.jpg *.png | head -10)


... or mapfile:



mapfile -t files < <(ls -1t *.jpg *.png | head -10)



otherwise:



files=()
while IFS= read -r f; do
files+=( "$f" )
done < <(ls -1t *.jpg *.png | head -10)


See also.




But, filenames are allowed to have linebreaks, so for reading filenames you should rather use find and use delimiter instead of ls -1 which uses n delimiter:



files=()
while IFS= read -r -d $'' f; do
files+=("$f")
done < <(
find . -maxdepth 1 -type f
-regextype posix-extended -iregex ".*.(jpg|png)$"
-printf '%T@t%P'
| sort -nrz
| head -z -n 10
| cut -z -f2-
)





share|improve this answer
































    0














    Instead of parsing ls, and if you can rely on the external stat utility and bash v4+ (for associative arrays), you could gather the list of files by inode, then gather a list of the most recent inodes, then build an array of filenames:



    shopt -s nocaseglob extglob
    declare -a filesbyinode=()
    for f in *.@(jpg|png); do filesbyinode[$(stat -c %i "$f")]=$f; done
    [ $#filesbyinode[@] -gt 0 ] || return
    declare wantedfiles=()
    for inodes in $(stat -c '%Y %i' *.@(jpg|png) | sort -k1,1rn | awk 'print $2' | head -10)
    do
    wantedfiles+=("$filesbyinode[$inodes]")
    done
    declare -p wantedfiles


    The first step is to set two shell options:




    • nocaseglob -- this enables the wildcard jpg to also match JPG (and JpG and ...)


    • extglob -- this enables the use of @(jpg|png) which means: matching filenames can end in either jpg or png (subject to nocaseglob, above)

    We then set up an empty associative array that indexes filenames by their inodes.



    The subsequent for loop builds up the filesbyinode array with inode indexes (the result of the stat command) and filenames as values.



    If there are no files, we bail out with a return -- adjust this as needed for your situation (perhaps an if/else).



    We then declare a (regular) array to hold the files that we're interested in. The next for loop iterates over the 10 most recent inodes and adds the corresponding filenames to the array. The 10 most recent inodes are determined by expanding the same wildcard as before, but asking only for the modification time (in seconds since the epoch) and the inodes; after sorting by the modification time in field #1 (largest/most recent first), we peel out the inodes in field #2 with awk and grab the top 10 of those with head.



    As a demonstration that the code is safe for various filenames:



    for i in $(seq 1 10); do touch $RANDOM.jpg $RANDOM.png $RANDOM.txt; sleep 1.1; done
    touch x.jpg '[x].jpg' 'a?b.jpg' 'a*b.jpg' '$( echo boom ).jpg'
    touch single'quote.jpg double"quote back\slash.jpg '*.jpg' ②.jpg


    ... the output is:



    declare -a wantedfiles=([0]="②.jpg" [1]="*.jpg" [2]="single'quote.jpg" [3]="back\slash.jpg" [4]=$'X240Y.jpg' [5]="[x].jpg" [6]="a?b.jpg" [7]="a*b.jpg" [8]="$( echo boom ).jpg" [9]="25396.jpg")


    (adjust the last filename for whatever $RANDOM came up with).






    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%2f512587%2fbash-command-to-create-array-with-the-10-most-recent-images-in-a-dir%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      4














      The correct syntax is:



      list=($(ls -t *.jpg *.png | head -10))
      echo First element: $list[0]
      echo Last element: $list[9]


      However, this solution will have problems with file names containing space characters (or any white space in general).






      share|improve this answer










      New contributor




      FedonKadifeli is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.




















      • Thanks, I assume I can overcome the whitespace issue by doing something like IFS=$(echo -en "nb") first?

        – RocketNuts
        15 hours ago















      4














      The correct syntax is:



      list=($(ls -t *.jpg *.png | head -10))
      echo First element: $list[0]
      echo Last element: $list[9]


      However, this solution will have problems with file names containing space characters (or any white space in general).






      share|improve this answer










      New contributor




      FedonKadifeli is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.




















      • Thanks, I assume I can overcome the whitespace issue by doing something like IFS=$(echo -en "nb") first?

        – RocketNuts
        15 hours ago













      4












      4








      4







      The correct syntax is:



      list=($(ls -t *.jpg *.png | head -10))
      echo First element: $list[0]
      echo Last element: $list[9]


      However, this solution will have problems with file names containing space characters (or any white space in general).






      share|improve this answer










      New contributor




      FedonKadifeli is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.










      The correct syntax is:



      list=($(ls -t *.jpg *.png | head -10))
      echo First element: $list[0]
      echo Last element: $list[9]


      However, this solution will have problems with file names containing space characters (or any white space in general).







      share|improve this answer










      New contributor




      FedonKadifeli is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this answer



      share|improve this answer








      edited 2 days ago





















      New contributor




      FedonKadifeli is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      answered 2 days ago









      FedonKadifeliFedonKadifeli

      515




      515




      New contributor




      FedonKadifeli is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      FedonKadifeli is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      FedonKadifeli is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.












      • Thanks, I assume I can overcome the whitespace issue by doing something like IFS=$(echo -en "nb") first?

        – RocketNuts
        15 hours ago

















      • Thanks, I assume I can overcome the whitespace issue by doing something like IFS=$(echo -en "nb") first?

        – RocketNuts
        15 hours ago
















      Thanks, I assume I can overcome the whitespace issue by doing something like IFS=$(echo -en "nb") first?

      – RocketNuts
      15 hours ago





      Thanks, I assume I can overcome the whitespace issue by doing something like IFS=$(echo -en "nb") first?

      – RocketNuts
      15 hours ago













      2














      For bash ≥ 4:



      To read output of a command into an array line by line, you should use readarray:



      readarray files < <(ls -1t *.jpg *.png | head -10)


      ... or mapfile:



      mapfile -t files < <(ls -1t *.jpg *.png | head -10)



      otherwise:



      files=()
      while IFS= read -r f; do
      files+=( "$f" )
      done < <(ls -1t *.jpg *.png | head -10)


      See also.




      But, filenames are allowed to have linebreaks, so for reading filenames you should rather use find and use delimiter instead of ls -1 which uses n delimiter:



      files=()
      while IFS= read -r -d $'' f; do
      files+=("$f")
      done < <(
      find . -maxdepth 1 -type f
      -regextype posix-extended -iregex ".*.(jpg|png)$"
      -printf '%T@t%P'
      | sort -nrz
      | head -z -n 10
      | cut -z -f2-
      )





      share|improve this answer





























        2














        For bash ≥ 4:



        To read output of a command into an array line by line, you should use readarray:



        readarray files < <(ls -1t *.jpg *.png | head -10)


        ... or mapfile:



        mapfile -t files < <(ls -1t *.jpg *.png | head -10)



        otherwise:



        files=()
        while IFS= read -r f; do
        files+=( "$f" )
        done < <(ls -1t *.jpg *.png | head -10)


        See also.




        But, filenames are allowed to have linebreaks, so for reading filenames you should rather use find and use delimiter instead of ls -1 which uses n delimiter:



        files=()
        while IFS= read -r -d $'' f; do
        files+=("$f")
        done < <(
        find . -maxdepth 1 -type f
        -regextype posix-extended -iregex ".*.(jpg|png)$"
        -printf '%T@t%P'
        | sort -nrz
        | head -z -n 10
        | cut -z -f2-
        )





        share|improve this answer



























          2












          2








          2







          For bash ≥ 4:



          To read output of a command into an array line by line, you should use readarray:



          readarray files < <(ls -1t *.jpg *.png | head -10)


          ... or mapfile:



          mapfile -t files < <(ls -1t *.jpg *.png | head -10)



          otherwise:



          files=()
          while IFS= read -r f; do
          files+=( "$f" )
          done < <(ls -1t *.jpg *.png | head -10)


          See also.




          But, filenames are allowed to have linebreaks, so for reading filenames you should rather use find and use delimiter instead of ls -1 which uses n delimiter:



          files=()
          while IFS= read -r -d $'' f; do
          files+=("$f")
          done < <(
          find . -maxdepth 1 -type f
          -regextype posix-extended -iregex ".*.(jpg|png)$"
          -printf '%T@t%P'
          | sort -nrz
          | head -z -n 10
          | cut -z -f2-
          )





          share|improve this answer















          For bash ≥ 4:



          To read output of a command into an array line by line, you should use readarray:



          readarray files < <(ls -1t *.jpg *.png | head -10)


          ... or mapfile:



          mapfile -t files < <(ls -1t *.jpg *.png | head -10)



          otherwise:



          files=()
          while IFS= read -r f; do
          files+=( "$f" )
          done < <(ls -1t *.jpg *.png | head -10)


          See also.




          But, filenames are allowed to have linebreaks, so for reading filenames you should rather use find and use delimiter instead of ls -1 which uses n delimiter:



          files=()
          while IFS= read -r -d $'' f; do
          files+=("$f")
          done < <(
          find . -maxdepth 1 -type f
          -regextype posix-extended -iregex ".*.(jpg|png)$"
          -printf '%T@t%P'
          | sort -nrz
          | head -z -n 10
          | cut -z -f2-
          )






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 2 days ago

























          answered 2 days ago









          RoVoRoVo

          3,960317




          3,960317





















              0














              Instead of parsing ls, and if you can rely on the external stat utility and bash v4+ (for associative arrays), you could gather the list of files by inode, then gather a list of the most recent inodes, then build an array of filenames:



              shopt -s nocaseglob extglob
              declare -a filesbyinode=()
              for f in *.@(jpg|png); do filesbyinode[$(stat -c %i "$f")]=$f; done
              [ $#filesbyinode[@] -gt 0 ] || return
              declare wantedfiles=()
              for inodes in $(stat -c '%Y %i' *.@(jpg|png) | sort -k1,1rn | awk 'print $2' | head -10)
              do
              wantedfiles+=("$filesbyinode[$inodes]")
              done
              declare -p wantedfiles


              The first step is to set two shell options:




              • nocaseglob -- this enables the wildcard jpg to also match JPG (and JpG and ...)


              • extglob -- this enables the use of @(jpg|png) which means: matching filenames can end in either jpg or png (subject to nocaseglob, above)

              We then set up an empty associative array that indexes filenames by their inodes.



              The subsequent for loop builds up the filesbyinode array with inode indexes (the result of the stat command) and filenames as values.



              If there are no files, we bail out with a return -- adjust this as needed for your situation (perhaps an if/else).



              We then declare a (regular) array to hold the files that we're interested in. The next for loop iterates over the 10 most recent inodes and adds the corresponding filenames to the array. The 10 most recent inodes are determined by expanding the same wildcard as before, but asking only for the modification time (in seconds since the epoch) and the inodes; after sorting by the modification time in field #1 (largest/most recent first), we peel out the inodes in field #2 with awk and grab the top 10 of those with head.



              As a demonstration that the code is safe for various filenames:



              for i in $(seq 1 10); do touch $RANDOM.jpg $RANDOM.png $RANDOM.txt; sleep 1.1; done
              touch x.jpg '[x].jpg' 'a?b.jpg' 'a*b.jpg' '$( echo boom ).jpg'
              touch single'quote.jpg double"quote back\slash.jpg '*.jpg' ②.jpg


              ... the output is:



              declare -a wantedfiles=([0]="②.jpg" [1]="*.jpg" [2]="single'quote.jpg" [3]="back\slash.jpg" [4]=$'X240Y.jpg' [5]="[x].jpg" [6]="a?b.jpg" [7]="a*b.jpg" [8]="$( echo boom ).jpg" [9]="25396.jpg")


              (adjust the last filename for whatever $RANDOM came up with).






              share|improve this answer



























                0














                Instead of parsing ls, and if you can rely on the external stat utility and bash v4+ (for associative arrays), you could gather the list of files by inode, then gather a list of the most recent inodes, then build an array of filenames:



                shopt -s nocaseglob extglob
                declare -a filesbyinode=()
                for f in *.@(jpg|png); do filesbyinode[$(stat -c %i "$f")]=$f; done
                [ $#filesbyinode[@] -gt 0 ] || return
                declare wantedfiles=()
                for inodes in $(stat -c '%Y %i' *.@(jpg|png) | sort -k1,1rn | awk 'print $2' | head -10)
                do
                wantedfiles+=("$filesbyinode[$inodes]")
                done
                declare -p wantedfiles


                The first step is to set two shell options:




                • nocaseglob -- this enables the wildcard jpg to also match JPG (and JpG and ...)


                • extglob -- this enables the use of @(jpg|png) which means: matching filenames can end in either jpg or png (subject to nocaseglob, above)

                We then set up an empty associative array that indexes filenames by their inodes.



                The subsequent for loop builds up the filesbyinode array with inode indexes (the result of the stat command) and filenames as values.



                If there are no files, we bail out with a return -- adjust this as needed for your situation (perhaps an if/else).



                We then declare a (regular) array to hold the files that we're interested in. The next for loop iterates over the 10 most recent inodes and adds the corresponding filenames to the array. The 10 most recent inodes are determined by expanding the same wildcard as before, but asking only for the modification time (in seconds since the epoch) and the inodes; after sorting by the modification time in field #1 (largest/most recent first), we peel out the inodes in field #2 with awk and grab the top 10 of those with head.



                As a demonstration that the code is safe for various filenames:



                for i in $(seq 1 10); do touch $RANDOM.jpg $RANDOM.png $RANDOM.txt; sleep 1.1; done
                touch x.jpg '[x].jpg' 'a?b.jpg' 'a*b.jpg' '$( echo boom ).jpg'
                touch single'quote.jpg double"quote back\slash.jpg '*.jpg' ②.jpg


                ... the output is:



                declare -a wantedfiles=([0]="②.jpg" [1]="*.jpg" [2]="single'quote.jpg" [3]="back\slash.jpg" [4]=$'X240Y.jpg' [5]="[x].jpg" [6]="a?b.jpg" [7]="a*b.jpg" [8]="$( echo boom ).jpg" [9]="25396.jpg")


                (adjust the last filename for whatever $RANDOM came up with).






                share|improve this answer

























                  0












                  0








                  0







                  Instead of parsing ls, and if you can rely on the external stat utility and bash v4+ (for associative arrays), you could gather the list of files by inode, then gather a list of the most recent inodes, then build an array of filenames:



                  shopt -s nocaseglob extglob
                  declare -a filesbyinode=()
                  for f in *.@(jpg|png); do filesbyinode[$(stat -c %i "$f")]=$f; done
                  [ $#filesbyinode[@] -gt 0 ] || return
                  declare wantedfiles=()
                  for inodes in $(stat -c '%Y %i' *.@(jpg|png) | sort -k1,1rn | awk 'print $2' | head -10)
                  do
                  wantedfiles+=("$filesbyinode[$inodes]")
                  done
                  declare -p wantedfiles


                  The first step is to set two shell options:




                  • nocaseglob -- this enables the wildcard jpg to also match JPG (and JpG and ...)


                  • extglob -- this enables the use of @(jpg|png) which means: matching filenames can end in either jpg or png (subject to nocaseglob, above)

                  We then set up an empty associative array that indexes filenames by their inodes.



                  The subsequent for loop builds up the filesbyinode array with inode indexes (the result of the stat command) and filenames as values.



                  If there are no files, we bail out with a return -- adjust this as needed for your situation (perhaps an if/else).



                  We then declare a (regular) array to hold the files that we're interested in. The next for loop iterates over the 10 most recent inodes and adds the corresponding filenames to the array. The 10 most recent inodes are determined by expanding the same wildcard as before, but asking only for the modification time (in seconds since the epoch) and the inodes; after sorting by the modification time in field #1 (largest/most recent first), we peel out the inodes in field #2 with awk and grab the top 10 of those with head.



                  As a demonstration that the code is safe for various filenames:



                  for i in $(seq 1 10); do touch $RANDOM.jpg $RANDOM.png $RANDOM.txt; sleep 1.1; done
                  touch x.jpg '[x].jpg' 'a?b.jpg' 'a*b.jpg' '$( echo boom ).jpg'
                  touch single'quote.jpg double"quote back\slash.jpg '*.jpg' ②.jpg


                  ... the output is:



                  declare -a wantedfiles=([0]="②.jpg" [1]="*.jpg" [2]="single'quote.jpg" [3]="back\slash.jpg" [4]=$'X240Y.jpg' [5]="[x].jpg" [6]="a?b.jpg" [7]="a*b.jpg" [8]="$( echo boom ).jpg" [9]="25396.jpg")


                  (adjust the last filename for whatever $RANDOM came up with).






                  share|improve this answer













                  Instead of parsing ls, and if you can rely on the external stat utility and bash v4+ (for associative arrays), you could gather the list of files by inode, then gather a list of the most recent inodes, then build an array of filenames:



                  shopt -s nocaseglob extglob
                  declare -a filesbyinode=()
                  for f in *.@(jpg|png); do filesbyinode[$(stat -c %i "$f")]=$f; done
                  [ $#filesbyinode[@] -gt 0 ] || return
                  declare wantedfiles=()
                  for inodes in $(stat -c '%Y %i' *.@(jpg|png) | sort -k1,1rn | awk 'print $2' | head -10)
                  do
                  wantedfiles+=("$filesbyinode[$inodes]")
                  done
                  declare -p wantedfiles


                  The first step is to set two shell options:




                  • nocaseglob -- this enables the wildcard jpg to also match JPG (and JpG and ...)


                  • extglob -- this enables the use of @(jpg|png) which means: matching filenames can end in either jpg or png (subject to nocaseglob, above)

                  We then set up an empty associative array that indexes filenames by their inodes.



                  The subsequent for loop builds up the filesbyinode array with inode indexes (the result of the stat command) and filenames as values.



                  If there are no files, we bail out with a return -- adjust this as needed for your situation (perhaps an if/else).



                  We then declare a (regular) array to hold the files that we're interested in. The next for loop iterates over the 10 most recent inodes and adds the corresponding filenames to the array. The 10 most recent inodes are determined by expanding the same wildcard as before, but asking only for the modification time (in seconds since the epoch) and the inodes; after sorting by the modification time in field #1 (largest/most recent first), we peel out the inodes in field #2 with awk and grab the top 10 of those with head.



                  As a demonstration that the code is safe for various filenames:



                  for i in $(seq 1 10); do touch $RANDOM.jpg $RANDOM.png $RANDOM.txt; sleep 1.1; done
                  touch x.jpg '[x].jpg' 'a?b.jpg' 'a*b.jpg' '$( echo boom ).jpg'
                  touch single'quote.jpg double"quote back\slash.jpg '*.jpg' ②.jpg


                  ... the output is:



                  declare -a wantedfiles=([0]="②.jpg" [1]="*.jpg" [2]="single'quote.jpg" [3]="back\slash.jpg" [4]=$'X240Y.jpg' [5]="[x].jpg" [6]="a?b.jpg" [7]="a*b.jpg" [8]="$( echo boom ).jpg" [9]="25396.jpg")


                  (adjust the last filename for whatever $RANDOM came up with).







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered 2 days ago









                  Jeff SchallerJeff Schaller

                  45.1k1164147




                  45.1k1164147



























                      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%2f512587%2fbash-command-to-create-array-with-the-10-most-recent-images-in-a-dir%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

                      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?