Monday, April 29, 2024
 Popular · Latest · Hot · Upcoming
11
rated 0 times [  11] [ 0]  / answers: 1 / hits: 59366  / 1 Year ago, fri, march 3, 2023, 12:44:56

I want to use find to find files in a set of folders restricted by wildcards, but where there are spaces in the path name.



From the command line, this is easy. The following examples all work.



find  te*/my files/more   -print
find te*/'my files'/more -print
find te*/my' 'files/more -print


These will find files in, for example, terminal/my files/more and tepid/my files/more.



However, I need this to be part of a script; what I need is something like this:



SEARCH='te*/my files/more'
find ${SEARCH} -print


Unfortunately, whatever I do, I don't seem to be able to mix wildcards and spaces in a find command within a script. The above example returns the following errors (note the unexpected doubling of the backslash):



find: ‘te*/my’: No such file or directory
find: ‘files/more’: No such file or directory


Trying to use quotes also fails.



SEARCH="te*/'my files'/more"
find ${SEARCH} -print


This returns the following errors, having ignored the meaning of the quotes:



find: ‘te*/'my’: No such file or directory
find: ‘files'/more’: No such file or directory


Here's one more example.



SEARCH='te*/my files/more'
find ${SEARCH} -print


As expected:



find: ‘te*/my’: No such file or directory
find: ‘files/more’: No such file or directory


Every variation that I've tried returns an error.



I have a workaround, which is potentially dangerous because it returns too many folders. I convert all spaces to a question mark (single-character wildcard) like this:



SEARCH='te*/my files/more'
SEARCH=${SEARCH// /?} # Convert every space to a question mark.
find ${SEARCH} -print


This is the equivalent of:



find te*/my?files/more -print


This returns not only the correct folders but also terse/myxfiles/more, which it's not supposed to.



How can I achieve what I'm trying to do? Google has not helped me :(


More From » scripts

 Answers
1

The exact same command should work fine in a script:



#!/usr/bin/env bash
find te*/my files/ -print


If you need to have it as a variable, it gets a bit more complex:



#!/usr/bin/env bash
search='te*/my files/'
eval find "$search" -print


WARNING:



Using eval like that is not safe and can result in executing arbitrary and possibly harmful code if your file names can contain certain characters. See bash FAQ 48 for details.



It's better to pass the path as an argument:



#!/usr/bin/env bash
find "$@" -name "file*"





Another approach is to avoid find altogether and use bash's extended globbing features and globs:



#!/usr/bin/env bash
shopt -s globstar
for file in te*/my files/**; do echo "$file"; done


The globstar bash option lets you use ** to match recursively:



globstar
If set, the pattern ** used in a pathname expansion con‐
text will match all files and zero or more directories
and subdirectories. If the pattern is followed by a /,
only directories and subdirectories match.


To make it act 100% like find and include dotfiles (hidden files), use



#!/usr/bin/env bash
shopt -s globstar
shopt -s dotglob
for file in te*/my files/**; do echo "$file"; done


You can even echo them directly without the loop:



echo te*/my files/**

[#23307] Saturday, March 4, 2023, 1 Year  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
shionnky

Total Points: 276
Total Questions: 104
Total Answers: 108

Location: Montenegro
Member since Thu, Jun 16, 2022
2 Years ago
shionnky questions
;