Loop through filenames without eval [closed]

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP












-3















In a shell script, if we want to loop over certain filenames, which we would get by shell globbing, as for example all MKV-files in all sub-directories starting with string "Example" – how can we do this without using eval?



E.g. while the following script does the loop



#!/usr/local/bin/zsh

for i in /media/mybook/Example*/; do;
t="ls "$i"*.mkv"
s=$(eval $t)
echo $s
done


is there a way to get rid of the eval?










share|improve this question















closed as unclear what you're asking by Kusalananda, wolf-revo-cats, Jeff Schaller, Stephen Harris, jimmij Feb 6 at 9:03


Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.


















  • Regarding you recent edit: Any chance that we get to see what you're actually trying to do so that we can modify our solutions?

    – Kusalananda
    Feb 5 at 21:18















-3















In a shell script, if we want to loop over certain filenames, which we would get by shell globbing, as for example all MKV-files in all sub-directories starting with string "Example" – how can we do this without using eval?



E.g. while the following script does the loop



#!/usr/local/bin/zsh

for i in /media/mybook/Example*/; do;
t="ls "$i"*.mkv"
s=$(eval $t)
echo $s
done


is there a way to get rid of the eval?










share|improve this question















closed as unclear what you're asking by Kusalananda, wolf-revo-cats, Jeff Schaller, Stephen Harris, jimmij Feb 6 at 9:03


Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.


















  • Regarding you recent edit: Any chance that we get to see what you're actually trying to do so that we can modify our solutions?

    – Kusalananda
    Feb 5 at 21:18













-3












-3








-3








In a shell script, if we want to loop over certain filenames, which we would get by shell globbing, as for example all MKV-files in all sub-directories starting with string "Example" – how can we do this without using eval?



E.g. while the following script does the loop



#!/usr/local/bin/zsh

for i in /media/mybook/Example*/; do;
t="ls "$i"*.mkv"
s=$(eval $t)
echo $s
done


is there a way to get rid of the eval?










share|improve this question
















In a shell script, if we want to loop over certain filenames, which we would get by shell globbing, as for example all MKV-files in all sub-directories starting with string "Example" – how can we do this without using eval?



E.g. while the following script does the loop



#!/usr/local/bin/zsh

for i in /media/mybook/Example*/; do;
t="ls "$i"*.mkv"
s=$(eval $t)
echo $s
done


is there a way to get rid of the eval?







shell-script wildcards eval






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Feb 24 at 4:14







wolf-revo-cats

















asked Feb 5 at 16:50









wolf-revo-catswolf-revo-cats

833933




833933




closed as unclear what you're asking by Kusalananda, wolf-revo-cats, Jeff Schaller, Stephen Harris, jimmij Feb 6 at 9:03


Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.









closed as unclear what you're asking by Kusalananda, wolf-revo-cats, Jeff Schaller, Stephen Harris, jimmij Feb 6 at 9:03


Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.














  • Regarding you recent edit: Any chance that we get to see what you're actually trying to do so that we can modify our solutions?

    – Kusalananda
    Feb 5 at 21:18

















  • Regarding you recent edit: Any chance that we get to see what you're actually trying to do so that we can modify our solutions?

    – Kusalananda
    Feb 5 at 21:18
















Regarding you recent edit: Any chance that we get to see what you're actually trying to do so that we can modify our solutions?

– Kusalananda
Feb 5 at 21:18





Regarding you recent edit: Any chance that we get to see what you're actually trying to do so that we can modify our solutions?

– Kusalananda
Feb 5 at 21:18










2 Answers
2






active

oldest

votes


















1














I'm confused why you would want to use eval here. You could just write s=$(ls "$i"*.mkv). But calling ls is pointless and would mangle file names. Just iterate over the files normally.



for dir in /media/mybook/Example*/; do;
if ! [ -d "$dir" ]; then continue; fi
for file in "$dir"/*.mkv; do
if ! [ -e "$file" ]; then continue; fi
echo "$file"
done
done


Note how "$dir" is within double quotes (so that any special characters such as spaces in the directory name remain as they are), but the * is outside the quotes so it's treated as a wildcard.



The lines with continue are there to skip the special case where the wildcard matches nothing. In sh, when a wildcard doesn't match, it's left as is, and so for sees a list of names with one element which is literally /media/mybook/Example*/ (for the outer loop). Some shells (ksh, bash, zsh) have a way to avoid this, for example in bash:



shopt -s nullglob
for dir in /media/mybook/Example*/; do;
for file in "$dir"/*.mkv; do
echo "$file"
done
done


If you're just processing the files and don't need to do anything for the directories, there's no point in having two nested loops.



for dir in /media/mybook/Example*/*.mkv; do
if ! [ -e "$file" ]; then continue; fi
echo "$file"
done


All these snippets act on files inside the Example* directories themselves, no in their subdirectories. If you want to traverse the directories recursively, see Kusalananda's answer.






share|improve this answer
































    0














    Using find:



    find /media/mybook/Example*/ -type f -name '*.mkv' -print


    Add -maxdepth 1 before -type f if you don't want to recurse into subdirectories.



    Or just a straight shell loop (will not work if there are many thousands of files), and assuming you only want to look in the first subdirectory level:



    for pathname in /media/mybook/Example*/*.mkv; do
    printf '%sn' "$pathname"
    done


    If you want to recurse down into subdirectories, using zsh or bash with its globstar shell option set (again, will not work for several thousand files):



    for pathname in /media/mybook/Example*/**/*.mkv; do
    printf '%sn' "$pathname"
    done


    Related:



    • Why *not* parse `ls` (and what do to instead)?


    To do something with the pathnames:



    With find:



    find /media/mybook/Example*/ -type f -name '*.mkv' -exec sh -c '
    for pathname do
    # Use "$pathname" here
    done' sh +


    ... where sh -c could obviously be changed to bash -c or zsh -c if you need to use any special features of these shells.



    Related:



    • Understanding the -exec option of `find`

    With a shell loop:



    for pathname in /media/mybook/Example*/*.mkv; do
    # Use "$pathname" here
    done



    Also related:



    • Why is looping over find's output bad practice?





    share|improve this answer































      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      1














      I'm confused why you would want to use eval here. You could just write s=$(ls "$i"*.mkv). But calling ls is pointless and would mangle file names. Just iterate over the files normally.



      for dir in /media/mybook/Example*/; do;
      if ! [ -d "$dir" ]; then continue; fi
      for file in "$dir"/*.mkv; do
      if ! [ -e "$file" ]; then continue; fi
      echo "$file"
      done
      done


      Note how "$dir" is within double quotes (so that any special characters such as spaces in the directory name remain as they are), but the * is outside the quotes so it's treated as a wildcard.



      The lines with continue are there to skip the special case where the wildcard matches nothing. In sh, when a wildcard doesn't match, it's left as is, and so for sees a list of names with one element which is literally /media/mybook/Example*/ (for the outer loop). Some shells (ksh, bash, zsh) have a way to avoid this, for example in bash:



      shopt -s nullglob
      for dir in /media/mybook/Example*/; do;
      for file in "$dir"/*.mkv; do
      echo "$file"
      done
      done


      If you're just processing the files and don't need to do anything for the directories, there's no point in having two nested loops.



      for dir in /media/mybook/Example*/*.mkv; do
      if ! [ -e "$file" ]; then continue; fi
      echo "$file"
      done


      All these snippets act on files inside the Example* directories themselves, no in their subdirectories. If you want to traverse the directories recursively, see Kusalananda's answer.






      share|improve this answer





























        1














        I'm confused why you would want to use eval here. You could just write s=$(ls "$i"*.mkv). But calling ls is pointless and would mangle file names. Just iterate over the files normally.



        for dir in /media/mybook/Example*/; do;
        if ! [ -d "$dir" ]; then continue; fi
        for file in "$dir"/*.mkv; do
        if ! [ -e "$file" ]; then continue; fi
        echo "$file"
        done
        done


        Note how "$dir" is within double quotes (so that any special characters such as spaces in the directory name remain as they are), but the * is outside the quotes so it's treated as a wildcard.



        The lines with continue are there to skip the special case where the wildcard matches nothing. In sh, when a wildcard doesn't match, it's left as is, and so for sees a list of names with one element which is literally /media/mybook/Example*/ (for the outer loop). Some shells (ksh, bash, zsh) have a way to avoid this, for example in bash:



        shopt -s nullglob
        for dir in /media/mybook/Example*/; do;
        for file in "$dir"/*.mkv; do
        echo "$file"
        done
        done


        If you're just processing the files and don't need to do anything for the directories, there's no point in having two nested loops.



        for dir in /media/mybook/Example*/*.mkv; do
        if ! [ -e "$file" ]; then continue; fi
        echo "$file"
        done


        All these snippets act on files inside the Example* directories themselves, no in their subdirectories. If you want to traverse the directories recursively, see Kusalananda's answer.






        share|improve this answer



























          1












          1








          1







          I'm confused why you would want to use eval here. You could just write s=$(ls "$i"*.mkv). But calling ls is pointless and would mangle file names. Just iterate over the files normally.



          for dir in /media/mybook/Example*/; do;
          if ! [ -d "$dir" ]; then continue; fi
          for file in "$dir"/*.mkv; do
          if ! [ -e "$file" ]; then continue; fi
          echo "$file"
          done
          done


          Note how "$dir" is within double quotes (so that any special characters such as spaces in the directory name remain as they are), but the * is outside the quotes so it's treated as a wildcard.



          The lines with continue are there to skip the special case where the wildcard matches nothing. In sh, when a wildcard doesn't match, it's left as is, and so for sees a list of names with one element which is literally /media/mybook/Example*/ (for the outer loop). Some shells (ksh, bash, zsh) have a way to avoid this, for example in bash:



          shopt -s nullglob
          for dir in /media/mybook/Example*/; do;
          for file in "$dir"/*.mkv; do
          echo "$file"
          done
          done


          If you're just processing the files and don't need to do anything for the directories, there's no point in having two nested loops.



          for dir in /media/mybook/Example*/*.mkv; do
          if ! [ -e "$file" ]; then continue; fi
          echo "$file"
          done


          All these snippets act on files inside the Example* directories themselves, no in their subdirectories. If you want to traverse the directories recursively, see Kusalananda's answer.






          share|improve this answer















          I'm confused why you would want to use eval here. You could just write s=$(ls "$i"*.mkv). But calling ls is pointless and would mangle file names. Just iterate over the files normally.



          for dir in /media/mybook/Example*/; do;
          if ! [ -d "$dir" ]; then continue; fi
          for file in "$dir"/*.mkv; do
          if ! [ -e "$file" ]; then continue; fi
          echo "$file"
          done
          done


          Note how "$dir" is within double quotes (so that any special characters such as spaces in the directory name remain as they are), but the * is outside the quotes so it's treated as a wildcard.



          The lines with continue are there to skip the special case where the wildcard matches nothing. In sh, when a wildcard doesn't match, it's left as is, and so for sees a list of names with one element which is literally /media/mybook/Example*/ (for the outer loop). Some shells (ksh, bash, zsh) have a way to avoid this, for example in bash:



          shopt -s nullglob
          for dir in /media/mybook/Example*/; do;
          for file in "$dir"/*.mkv; do
          echo "$file"
          done
          done


          If you're just processing the files and don't need to do anything for the directories, there's no point in having two nested loops.



          for dir in /media/mybook/Example*/*.mkv; do
          if ! [ -e "$file" ]; then continue; fi
          echo "$file"
          done


          All these snippets act on files inside the Example* directories themselves, no in their subdirectories. If you want to traverse the directories recursively, see Kusalananda's answer.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Feb 5 at 18:29

























          answered Feb 5 at 17:53









          GillesGilles

          539k12810911606




          539k12810911606























              0














              Using find:



              find /media/mybook/Example*/ -type f -name '*.mkv' -print


              Add -maxdepth 1 before -type f if you don't want to recurse into subdirectories.



              Or just a straight shell loop (will not work if there are many thousands of files), and assuming you only want to look in the first subdirectory level:



              for pathname in /media/mybook/Example*/*.mkv; do
              printf '%sn' "$pathname"
              done


              If you want to recurse down into subdirectories, using zsh or bash with its globstar shell option set (again, will not work for several thousand files):



              for pathname in /media/mybook/Example*/**/*.mkv; do
              printf '%sn' "$pathname"
              done


              Related:



              • Why *not* parse `ls` (and what do to instead)?


              To do something with the pathnames:



              With find:



              find /media/mybook/Example*/ -type f -name '*.mkv' -exec sh -c '
              for pathname do
              # Use "$pathname" here
              done' sh +


              ... where sh -c could obviously be changed to bash -c or zsh -c if you need to use any special features of these shells.



              Related:



              • Understanding the -exec option of `find`

              With a shell loop:



              for pathname in /media/mybook/Example*/*.mkv; do
              # Use "$pathname" here
              done



              Also related:



              • Why is looping over find's output bad practice?





              share|improve this answer





























                0














                Using find:



                find /media/mybook/Example*/ -type f -name '*.mkv' -print


                Add -maxdepth 1 before -type f if you don't want to recurse into subdirectories.



                Or just a straight shell loop (will not work if there are many thousands of files), and assuming you only want to look in the first subdirectory level:



                for pathname in /media/mybook/Example*/*.mkv; do
                printf '%sn' "$pathname"
                done


                If you want to recurse down into subdirectories, using zsh or bash with its globstar shell option set (again, will not work for several thousand files):



                for pathname in /media/mybook/Example*/**/*.mkv; do
                printf '%sn' "$pathname"
                done


                Related:



                • Why *not* parse `ls` (and what do to instead)?


                To do something with the pathnames:



                With find:



                find /media/mybook/Example*/ -type f -name '*.mkv' -exec sh -c '
                for pathname do
                # Use "$pathname" here
                done' sh +


                ... where sh -c could obviously be changed to bash -c or zsh -c if you need to use any special features of these shells.



                Related:



                • Understanding the -exec option of `find`

                With a shell loop:



                for pathname in /media/mybook/Example*/*.mkv; do
                # Use "$pathname" here
                done



                Also related:



                • Why is looping over find's output bad practice?





                share|improve this answer



























                  0












                  0








                  0







                  Using find:



                  find /media/mybook/Example*/ -type f -name '*.mkv' -print


                  Add -maxdepth 1 before -type f if you don't want to recurse into subdirectories.



                  Or just a straight shell loop (will not work if there are many thousands of files), and assuming you only want to look in the first subdirectory level:



                  for pathname in /media/mybook/Example*/*.mkv; do
                  printf '%sn' "$pathname"
                  done


                  If you want to recurse down into subdirectories, using zsh or bash with its globstar shell option set (again, will not work for several thousand files):



                  for pathname in /media/mybook/Example*/**/*.mkv; do
                  printf '%sn' "$pathname"
                  done


                  Related:



                  • Why *not* parse `ls` (and what do to instead)?


                  To do something with the pathnames:



                  With find:



                  find /media/mybook/Example*/ -type f -name '*.mkv' -exec sh -c '
                  for pathname do
                  # Use "$pathname" here
                  done' sh +


                  ... where sh -c could obviously be changed to bash -c or zsh -c if you need to use any special features of these shells.



                  Related:



                  • Understanding the -exec option of `find`

                  With a shell loop:



                  for pathname in /media/mybook/Example*/*.mkv; do
                  # Use "$pathname" here
                  done



                  Also related:



                  • Why is looping over find's output bad practice?





                  share|improve this answer















                  Using find:



                  find /media/mybook/Example*/ -type f -name '*.mkv' -print


                  Add -maxdepth 1 before -type f if you don't want to recurse into subdirectories.



                  Or just a straight shell loop (will not work if there are many thousands of files), and assuming you only want to look in the first subdirectory level:



                  for pathname in /media/mybook/Example*/*.mkv; do
                  printf '%sn' "$pathname"
                  done


                  If you want to recurse down into subdirectories, using zsh or bash with its globstar shell option set (again, will not work for several thousand files):



                  for pathname in /media/mybook/Example*/**/*.mkv; do
                  printf '%sn' "$pathname"
                  done


                  Related:



                  • Why *not* parse `ls` (and what do to instead)?


                  To do something with the pathnames:



                  With find:



                  find /media/mybook/Example*/ -type f -name '*.mkv' -exec sh -c '
                  for pathname do
                  # Use "$pathname" here
                  done' sh +


                  ... where sh -c could obviously be changed to bash -c or zsh -c if you need to use any special features of these shells.



                  Related:



                  • Understanding the -exec option of `find`

                  With a shell loop:



                  for pathname in /media/mybook/Example*/*.mkv; do
                  # Use "$pathname" here
                  done



                  Also related:



                  • Why is looping over find's output bad practice?






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Feb 5 at 16:59

























                  answered Feb 5 at 16:54









                  KusalanandaKusalananda

                  133k17253416




                  133k17253416












                      Popular posts from this blog

                      How to check contact read email or not when send email to Individual?

                      Displaying single band from multi-band raster using QGIS

                      How many registers does an x86_64 CPU actually have?