Loop through filenames without eval [closed]
Clash Royale CLAN TAG#URR8PPP
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
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.
add a comment |
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
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
add a comment |
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
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
shell-script wildcards eval
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
add a comment |
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
add a comment |
2 Answers
2
active
oldest
votes
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.
add a comment |
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?
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
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.
add a comment |
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.
add a comment |
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.
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.
edited Feb 5 at 18:29
answered Feb 5 at 17:53
GillesGilles
539k12810911606
539k12810911606
add a comment |
add a comment |
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?
add a comment |
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?
add a comment |
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?
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?
edited Feb 5 at 16:59
answered Feb 5 at 16:54
KusalanandaKusalananda
133k17253416
133k17253416
add a comment |
add a comment |
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