我想用来find
在一组受通配符限制的文件夹中查找文件,但路径名中有空格。
从命令行来看,这很容易。以下示例均可用。
find te*/my\ files/more -print
find te*/'my files'/more -print
find te*/my' 'files/more -print
例如,它们将在terminal/my files/more
和中找到文件tepid/my files/more
。
但是,我需要将其作为脚本的一部分;我需要的是类似这样的内容:
SEARCH='te*/my\ files/more'
find ${SEARCH} -print
不幸的是,无论我做什么,我似乎都无法在find
脚本中的命令中混合使用通配符和空格。上面的示例返回以下错误(请注意意外的反斜杠重复):
find: ‘te*/my\\’: No such file or directory
find: ‘files/more’: No such file or directory
尝试使用引号也失败。
SEARCH="te*/'my files'/more"
find ${SEARCH} -print
忽略引号的含义,这将返回以下错误:
find: ‘te*/'my’: No such file or directory
find: ‘files'/more’: No such file or directory
再举一个例子。
SEARCH='te*/my files/more'
find ${SEARCH} -print
正如预期的那样:
find: ‘te*/my’: No such file or directory
find: ‘files/more’: No such file or directory
我尝试过的每种变化都会返回错误。
我有一个解决方法,但这种方法可能很危险,因为它会返回太多文件夹。我将所有空格转换为问号(单字符通配符),如下所示:
SEARCH='te*/my files/more'
SEARCH=${SEARCH// /?} # Convert every space to a question mark.
find ${SEARCH} -print
这相当于:
find te*/my?files/more -print
这不仅会返回正确的文件夹terse/myxfiles/more
,而且还会返回不应该返回的。
我该如何实现我想要做的事情?谷歌没有帮助我 :(
答案1
完全相同的命令在脚本中应该可以正常工作:
#!/usr/bin/env bash
find te*/my\ files/ -print
如果你需要要将其作为变量,它会变得更加复杂:
#!/usr/bin/env bash
search='te*/my\ files/'
eval find "$search" -print
警告:
使用eval
这种方法并不安全,如果文件名包含特定字符,则可能导致执行任意且可能有害的代码。请参阅bash 常见问题 48了解详情。
最好将路径作为参数传递:
#!/usr/bin/env bash
find "$@" -name "file*"
另一种方法是完全避免find
并使用 bash 的扩展通配符功能和通配符:
#!/usr/bin/env bash
shopt -s globstar
for file in te*/my\ files/**; do echo "$file"; done
bashglobstar
选项允许您使用**
递归匹配:
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.
为了使其 100% 像查找并包含点文件(隐藏文件)一样运行,请使用
#!/usr/bin/env bash
shopt -s globstar
shopt -s dotglob
for file in te*/my\ files/**; do echo "$file"; done
您可以echo
直接甚至不使用循环来均匀分布它们:
echo te*/my\ files/**
答案2
那么数组怎么样?
$ tree Desktop/ Documents/
Desktop/
└── my folder
└── more
└── file
Documents/
└── my folder
├── folder
└── more
5 directories, 1 file
$ SEARCH=(D*/my\ folder)
$ find "${SEARCH[@]}"
Desktop/my folder
Desktop/my folder/more
Desktop/my folder/more/file
Documents/my folder
Documents/my folder/more
Documents/my folder/folder
(*)
扩展为与通配符匹配的任何内容的数组。并"${SEARCH[@]}"
扩展为数组中的所有元素 ( [@]
),每个元素都单独用引号引起来。
后来我才意识到 find 本身应该能够做到这一点。例如:
find . -path 'D*/my folder/more/'
答案3
现在它有点过时了,但是,如果它可以帮助任何人解决这个问题,那么使用 RE 的排序符号[[.space.]]
而不$SEARCH
在查找命令行参数中引用变量,只要扩展路径名中没有特殊字符代替星号就可以工作。
set -x
mkdir -p te{flon,nnis,rrine}/my\ files/more
SEARCH=te*/my[[.space.]]files/more
find $SEARCH
得到以下结果:
+ mkdir -p 'teflon/my files/more' 'tennis/my files/more' 'terrine/my files/more'
+ SEARCH='te*/my[[.space.]]files/more'
+ find 'teflon/my files/more' 'tennis/my files/more' 'terrine/my files/more'
teflon/my files/more
tennis/my files/more
terrine/my files/more
为了防止不需要的字符被覆盖,可以*
用任何排序元素(字符)替换星号():
set -x
mkdir -p -- te{,-,_}{flon,nnis,rrine}/my\ files/more
SEARCH=te[[:alnum:][.space.][.hyphen.][.underscore.]]*/my[[.space.]]files/more
find $SEARCH
得到以下结果:
+ mkdir -p -- 'teflon/my files/more' 'tennis/my files/more' 'terrine/my files/more' \
'te-flon/my files/more' 'te-nnis/my files/more' 'te-rrine/my files/more' \
'te_flon/my files/more' 'te_nnis/my files/more' 'te_rrine/my files/more'
+ SEARCH='te[[:alnum:][.space.][.hyphen.][.underscore.]]*/my[[.space.]]files/more'
+ find 'te-flon/my files/more' 'te_flon/my files/more' 'teflon/my files/more' \
'te-nnis/my files/more' 'te_nnis/my files/more' 'tennis/my files/more' \
'te-rrine/my files/more' 'te_rrine/my files/more' 'terrine/my files/more'
te-flon/my files/more
te_flon/my files/more
teflon/my files/more
te-nnis/my files/more
te_nnis/my files/more
tennis/my files/more
te-rrine/my files/more
te_rrine/my files/more
terrine/my files/more
请注意,为了缩短行, 可以用或[.hyphen.]
替换 ,也 可以用或替换。[.-.]
-
[.underscore.]
[._.]
_
\
为了便于阅读,我自己添加了用反斜杠 ( ) 截断的行。
答案4
我终于找到了答案。
在所有空格前添加反斜杠:
SEARCH='te*/my files/more'
SEARCH=${SEARCH// /\\ }
此时,SEARCH
包含te*/my\ files/more
。
然后,使用eval
。
eval find ${SEARCH} -print
就这么简单!使用可以绕过变量的eval
解释。${SEARCH}