Is there any way to change the following string so I don't get any problems when there are files/folders with spaces in them?
files=`find ~/$folder -name "*@*" -type f`
I'd prefer if ther开发者_JS百科e was a solution that wouldn't have to involve having to change other parts of my code but this line of code, as everything seems to be working correctly, apart from this minor detail.
Thanks
EDIT: Here is the code in a bit more detail:
abc=( $(find "$pasta" -name "$ficheiro_original@*" -type f) )
abc_length=${#abc[@]}
If you are not using those file names later in your script , just iterate them and process on the fly.
find ~/$folder -name "*@*" -type f | while read -r FILE
do
echo "do you stuff"
done
otherwise, you can set IFS
IFS=$'\n'
files=$(find ~/$folder -name "*@*" -type f)
Update:
$ IFS=$'\n'
$ a=($(find . -type f ))
$ echo ${#a[@]}
14
You'd have to make some changes, but to deal with arbitrary names, think in terms of using the GNU Find option -print0
, etc.
find ~/$folder -name "*@*" -type f -print0 |
while read -d '^@' file
do
echo "<<$file>>"
done
(Where the single byte represented as '^@
' is actually an ASCII NUL ('\0'; enter with Control-V Control-Shift-@).
find ~/$folder -name "*@*" -type f -print0 |
while read -d '' file
do
echo "<<$file>>"
done
The empty string for the delimiter means 'use the zero byte, ASCII NUL, as the delimiter' and is appropriate for parsing 'find ... -print0
' output. (Thanks Dennis Williamson for the tip.)
This allows you to read any arbitrary names. You should probably use a bash array to hold the names, but that implies some changes further down the script.
(Given the comment response that only spaces have to be worried about, this might be overkill, though using read
to process lines with the names is a key part of the operation, and using an array would probably make life simpler.)
If you need a list of files that might have spaces in the names, you pretty much have to store them as an array, rather than just a string. Create the array with something like this:
saveIFS="$IFS"; IFS=$'\n'; files=( $(find ~/"$folder" -name "*@*" -type f) ); IFS="$saveIFS"
and then you'll have to modify the rest of the script to use files as an array rather than a string, and it (and other filenames) should always be in double-quotes to keep spaces from being mistaken as separators. For instance, anyplace you're currently using $files
, replace that with "${files[@]}"
ls "${files[@]}"
for f in "${files[@]}"; do
ls "$f"
done
echo "found ${#files[@]} files"
Here is another way to get around without changing the rest of code:
# files=($(find))
eval "files=($(find -printf '"%h/%f" '))"
for f in "${files[@]}"; do
echo "$f"
done
It's dirty and will not work for filename with special characters, e.g. "
. It uses eval
to evaluate a string of a Bash array and -printf
of find
to form that string.
I personally prefer changing $IFS
, just FYI.
To read file names with spaces into a Bash array variable, you could use the "read" builtin command as well:
printf '%q\n' "$IFS"
IFS=$'\n' read -r -d "" -a abc <<< "$(find ~/$folder -name "*@*" -type f)"
IFS=$'\n' read -r -d "" -a abc < <(find ~/$folder -name "*@*" -type f) # alternative
abc_length=${#abc[@]}
for ((i=1; i <= ${#abc[@]}; i++)); do echo "$i: ${abc[i-1]}"; done
printf '%q\n' "$IFS"
Note that the scope of the newly set IFS variable is limited to the execution of the read command (which leaves the original IFS variable intact).
精彩评论