In bash, I think I know how to iterate over an array of strings containing spaces:
~ $ arr=( "/home/user/Images/three parts dirname/ccc.png" "/home/user/Images/three parts dirname/bbb.png" "/home/user/Images/three parts dirname/aaa.png" )
~ $ for i in "${arr[@]}"; do echo "$i"; done
/home/user/Images/three parts dirname/ccc.png
/home/user/Images/three parts dirname/bbb.png
/home/user/Images/three parts dirname/aaa.png
I want to do something similar in a script that uses find
. So I'm doing...
~ $ d="/home/user/Images/three parts name"
~ $ arr=( $(find -L "$d" -maxdepth 1 -iname '*.jp*g' -o -iname '*.png' -printf '"%p" ') )
...because the command find -L "$d" -maxdepth 1 -iname '*.jp*g' -o -iname '*.png' -printf '"%p" '
gives exacltly:
"/home/user/Images/three part name/ccc.png" "/home/user/Images/three part name/bbb.png" "/home/user/Images/three part name/aaa.png"
The problem is that in this case I have the result below:
~ $ for i in "${arr[@]}"; do echo "$i"; done
"/home/user/Images/three
parts
name/ccc.png"
"/home/user/Images/three
parts
name/bbb.png"
"/home/user/Images/three
parts
name/aaa.png"
So I cannot iterate over those files successfully. I know I can avoid spaces in dirs and files names (and I barely have any) but I wanted the script to work anyway, just in case.
What I mean is: why If I use find
to define the array, the 1st item, i.e., is
"/home/user/Images/three
and not
/home/user/Images/three parts dirname/ccc.png
?
It seems that with find
the spaces in the dir names are "hard coded" and/or the double quotes are part of the strings (separated by spaces) themselves.
EDIT here for clarity:
I accepted the answer using find
. It has to be corrected adding escaped brackets though, according to stackoverflow.com/a/6957310/1865860. I also wanted to further process the find results, so I had to rely on stackoverflow.com/a/11789688/1865860.
The final output looks like:
readarray -d $'\0' TOT_IMAGES < <(find -L "$i" -maxdepth 1 \( -iname '*.jp*g' -o -iname '*.png' -o -iname '*.gif' -o -iname '*.tif*' \) -print0);
IFS=$'\n';
SORTED_IMAGES=($(sort <<<"${TOT_IMAGES[*]}"));
TOP4_IMAGES=($(head -n4 <<<"${SORTED_IMAGES[*]}"));
unset IFS
CodePudding user response:
You could do this with pure bash
, without using the find
:
shopt -s nullglob nocaseglob
arr=("$d"/{*.png,*.jp*g})
CodePudding user response:
You can use find
with print0
option to have ASCII NUL character separator (instead of NL) and then use readarray
readarray -d $'\0' arr < <(find -L "$d" -maxdepth 1 -iname '*.jp*g' -o -iname '*.png' -print0)
so you don't have to worry about the spaces.