Reputation: 3610
I have the following bash script:
#!/bin/bash
test=$(find . -name "*.cfg")
echo ${#test[@]}
And the output is simply 1. However, find returns 8 elements and when used in a loop their names are displayed correctly:
for f in $(find . -name "*.cfg")
do
echo $f
done
How can I check the size of the test
array? Thank you!
Upvotes: 2
Views: 251
Reputation: 46823
The only safe way to store the output of find
into an array is to use the -print0
extension, which is not POSIX (yet, GNU find
supports it):
files=()
while IFS= read -r -d '' file; do
files+=( "$file" )
done < <(
find . -name '*.cfg' -print0
)
printf 'There are %d files found.\n' "${#files[@]}"
If you only want the number of files found, you can use this (using -printf
, not POSIX but supported by GNU):
xfiles=$(find . -name '*.cfg' -printf 'x')
printf 'There are %d files found.\n' "${#xfiles}"
or in a POSIX-compliant way:
xfiles=$(find . -name '*.cfg' -exec printf "%.sx" {} +)
printf 'There are %d files found.\n' "${#xfiles}"
Now Bash≥4 can deal with this on its own:
shopt -s globstar nullglob
files=( **/*.cfg )
printf 'There are %d files found.\n' "${#files[@]}"
(though it might be slower than find
).
Upvotes: 3
Reputation: 531075
Since you aren't using any other feature of find
, I would use a glob to create the array instead:
# Bash 4+
shopt -s globstar
test=( **/*.cfg )
The globstar
option enables the pattern **
, which matches 0 or more directories in a path. It allows for recursive matching with a directory hierarchy, so **/*.cfg
would match ./foo.cfg
, ./bar/hello world.cfg
, etc. Each matched file, regardless of whatever special characters may exist in the file name, will be treated as a single array entry.
If you need to support an older version of bash
, there are more complicated techniques you can use assuming your version of find
supports -print0
or something similar.
Upvotes: 2
Reputation: 80931
test
is a string (not an array).
You are using [@]
on it which isn't doing anything useful and is breaking things for you. Drop it.
You want ${#test}
to get the length of the string. If you want an array you need to do that differently.
You do not want to parse/read/for
-loop/etc. over the output of find that way though (it isn't safe for "odd" file names).
See http://mywiki.wooledge.org/BashFAQ/001 for ways to do that safely (specifically see the section about -print0
).
Upvotes: 2
Reputation: 20456
You have to create an array first, try this:
test=($(find . -name "*.cfg"))
echo ${#test[@]}
Upvotes: -1