I want to do this: readarray var1 < <(find "/path/to/dir" \( $var2 \) | sort)
echo $var2
user@domain:~# -name "*.avi" -o -name "*.mkv"
Unfortunately, my script does not work. Please, tell me where I do a mistake.
I want to do this: readarray var1 < <(find "/path/to/dir" \( $var2 \) | sort)
echo $var2
user@domain:~# -name "*.avi" -o -name "*.mkv"
Unfortunately, my script does not work. Please, tell me where I do a mistake.
Use an array:
var2=( -name "*.avi" -o -name "*.mkv" )
readarray var1 < <(find "/path/to/dir" \( "${var2[@]}" \) | sort)
See the somewhat related How can we run a command stored in a variable?
var1, so it's not like you could port this code to a shell that doesn't support arrays
– steeldriver
Jul 13 '19 at 23:38
To get all names beneath the path /path/to/dir as a sorted list in bash:
shopt -s globstar nullglob dotglob
names=( /path/to/dir/** )
The globstar shell option in bash enables the use of the ** glob, which works similarly as * but matches across / in pathnames (i.e., it matches "recursively" down into directories). The nullglob shell option makes it so that if a shell glob does not match any name, it is removed completely (the default is to keep the unexpanded pattern). The dotglob option causes hidden filenames to be matched by default.
The resulting expansion of a shell glob is lexicographically ordered, as is the default output of sort, so no piping of names to sort is necessary.
To get the names that has the filename suffixes .avi or .mkv, use
shopt -s globstar nullglob dotglob extglob
names=( /path/to/dir/**/*.@(avi|mkv) )
Here, I've added the extglob shell option, which allows for using extended globbing pattern. The pattern @(avi|mkv) means "either avi or mkv", so the full pattern would match any name beneath /path/to/dir that ends with either .avi or .mkv. The resulting array would be sorted.
find would be useful if you need to do things with the found names, or if you need to incorporate specific filetype tests. For example, if you need to make sure you're only matching only regular files, use
find /path/to/dir -type f \( -name '*.avi' -o -name '*.mkv' \)
Given the two filename suffixes avi and mkv in an array called suffix, the -name tests can be constructed as an array:
suffix=( avi mkv )
nametest=( -false ) # assumes GNU find here
for suf in "${suffix[@]}"; do
nametest+=( -o -name ".$suf" )
done
find /path/to/dir -type f \( "${nametest[@]}" \)
It is almost never correct to save the output of find in a variable when you actually want to do things to the found names. Instead, use -exec to carry out the action:
find /path/to/dir -type f \( "${nametest[@]}" \) -exec sh -c '
for pathname do
# do something with "$pathname" here
done' sh {} +
For further reading, see
names=( /path/to/dir/**/*.@(avi|mkv) ) First part is for zsh ? And really, It is easier, but can your case be more dynamic? I mean names=( /path/to/dir/**/*.@(avi|mkv) ) . Can I use a variable type of array (or another) instead @(avi|mkv) ? Just I save suffixes to variable and use in another part of code too.
– xUr
Jul 14 '19 at 08:26
zshshell in a much more convenient and safe way which would not rely on the pathnames being sane (containing no newlines). – Kusalananda Jul 13 '19 at 23:38