提问人:Rubberducky 提问时间:11/15/2023 最后编辑:AshokRubberducky 更新时间:11/18/2023 访问量:47
返回的文件与指定的模式不匹配
files being returned with find which do not match the pattern specified
问:
我的目的是显示目录和文件(带有 .dat 或 .DAT 文件扩展名仅在树结构中。我的 bash 脚本中的以下代码示例返回这些文件,但也返回扩展名为 .txt / .xmlfd 的文件。谁能指出我的代码有什么问题?
sudo -${user} sh -c 'cd '${userdirectory}'; find . -type f | grep -i '*.dat' | sort -u | xargs tree -L 3 -C'
sudo -${user} sh -c 'cd '${userdirectory}'; find . -type f -iname '*.dat' -exec dirname {} \; | sort -u | xargs tree -L 3 -C'
sudo -${user} sh -c 'cd '${userdirectory}'; find . -type f -name '*.[dD][aA][tT]' -exec dirname {} \; | sort -u | xargs tree -L 3 -C'
答:
你的 grep 正则表达式没有多大意义:正则表达式开头的星号具有字面星号的含义,并且仅当生成的文件名之一包含星号时才会匹配。句点与任何字符匹配,因此您基本上搜索子字符串,例如文件名中的 或。如果搜索名称以 结尾的文件,则 grep 表示:find
grep
*xdat
*%dat
.dat
[.]dat$
grep -i '[.]dat$'
匹配一个文字点,并将匹配项锚定在行的末尾。[.]
$
或者,您可以通过指定 glob 模式来进行选择,find
find .... -iname '*.dat'
或者,如果您确实想使用正则表达式,则通过
find .... -iregex '[.]dat$'
当然,所有这些都要求您的文件名不包含换行符。
在任何情况下,请确保引号正确:如果整个字符串用单引号括起来,则需要对 find 或 grep 命令的单引号进行转义。
谁能指出我的代码有什么问题?
tree
期望目录,所以你的基本前提被打破了。
你不能以这种方式在特定的文件参数列表中调用它,但看起来你真正需要的只是让它自己做那个选择。-P
$: tree --version # in case anyone needs to know
tree v1.6.0 (c) 1996 - 2011 by Steve Baker, Thomas Moore, Francesc Rocher, Kyosuke Tokoro
$: tree -L 3 -C -P '*.[dD][aA][tT]' # or '*.dat|*.DAT'
.
├── a.DAT
├── a.dat
├── b.DAT
├── b.dat
└── foo
├── a.DAT
├── a.dat
├── b.DAT
├── b.dat
└── bar
├── a.DAT
├── a.dat
├── b.DAT
├── b.dat
└── baz
(正在工作:)-L 3
$: printf "%s\n" foo/bar/baz/*
foo/bar/baz/a.dat
foo/bar/baz/a.DAT
foo/bar/baz/b.dat
foo/bar/baz/b.DAT
为了详细说明您实际提出的问题,让我们看看您遇到的一些具体问题。
sudo -${user} sh -c 'cd '${userdirectory}'; find . -type f | grep -i '*.dat' | sort -u | xargs tree -L 3 -C'
- 我想你的意思是.
sudo -u $user
- 修正你的报价。
- 修复正则表达式(或其他文件限制方式)。
tree
需要目录,见上文。
解决每个问题 -
sudo -${user}
将用户名作为一堆选项传递,其中一些可能需要也可能不需要参数并在语法上中断 - 您应该希望它们这样做。你想要的是
sudo -u "${user}" ...
大多数引号不嵌套。最佳做法是引用变量,除非您有充分的、具体的理由不这样做,因此请尽可能在单倍和双倍之间切换。
请记住,单引号会阻止变量插值,因此,如果变量存在于当前环境中,则需要在解析行时让 shell 插入它,然后才能将生成的命令发送到 .sudo
请注意,如果一组引号在另一组引号内,则外部通常会定义插值和内部引号规则:
$: foo='bar baz'; echo "foo='$foo'"; echo 'foo="$foo"'; echo "foo=\"$foo\" "
foo='bar baz'
foo="$foo"
foo="bar baz"
因此
sudo -u "${user}" sh -c "cd '${userdirectory}'; : do stuff;"
这将传递单引号以保护 中的任何嵌入空格,但在将整个内容传递给 之前仍会插入 as 的值。${userdirectory}
${userdirectory}
sudo
请注意,如上所述,如果失败,它将在任何地方执行任何剩余的命令。通常,如果可能,最好检查一下。例如,cd
sudo -u "${user}" sh -c "if cd '${userdirectory}'; then : do stuff; else echo aborting; fi"
给定的将返回当前目录下的所有纯文件。正如 user1934428 所指出的,将允许您返回不区分大小写的匹配项,而无需单独的 .find
-iname
grep
sudo -u "${user}" sh -c "if cd "${userdirectory}"; then find . -type f -iname '*.dat'; fi" # watch those quotes
顺便说一句,使用正则表达式,而不是 globs。你应该是 - 尽管再次,正如 user1934428 指出的那样,在做这种事情时不要使用,即使你更喜欢正则表达式而不是通配;您仍然可以以大致相同的方式消除额外的过程,但使用 代替 ,如grep
grep -i '*.dat'
grep -i '\.dat$'
grep
-iregex '[.]dat$'
-iname '*.dat'
sudo -u "${user}" sh -c "if cd "${userdirectory}"; then find . -type f -iregex '[.]dat$'; fi"
通过一个简单的词汇来传递任何一个,也可能做不到你想做的事,但如果你搜索,这确实是另一个广泛可用的讨论。sort
正如我们上面提到的,根本不是你需要的,所以也变得多余(没关系)。如果你正在做一些它有用的东西,c.f. BashFAQ #20 有很好的例子和解释。find
xargs
-exec
...但你不需要或树-P'模式。find
xargs. Just call
with the
sudo -u "${user}" sh -c "if cd '${userdirectory}'; then tree -Cv -L 3 -P '*.[dD][aA][tT]' --prune --dirsfirst; else echo Failed cd, aborting; fi"
请注意,它是通格的,所以它不是一个真正的正则表达式,但它也可能没有与 shell 相同的所有玩具。例如,设置似乎不起作用,因为它可能没有复制到 的 subshell 中。tree
shopt -s nocaseglob
tree
这意味着要匹配您可以使用的大写和小写,但这不会匹配名为 的文件,而 -P '*.[分差][aA][tT]'将。相应地选择。-P '*.dat|*.DAT'
foo.Dat
-v
应该有助于排序。尝试将输出放在所需位置,例如消除输出中没有任何有效命中的目录。--prune
--dirsfirst
评论
sudo -u ${user} sh -c 'cd '${userdirectory}'; find . -type f -iname "*.dat" -o -iname "*.DAT" | sort -u | xargs tree -L 3 -C'