开发者

Spaces in path names giving trouble with Find in Bash. Any *simple* work-around?

开发者 https://www.devze.com 2023-01-19 04:08 出处:网络
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?

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).

0

精彩评论

暂无评论...
验证码 换一张
取 消