返回的文件与指定的模式不匹配

files being returned with find which do not match the pattern specified

提问人:Rubberducky 提问时间:11/15/2023 最后编辑:AshokRubberducky 更新时间:11/18/2023 访问量:47

问:

我的目的是显示目录和文件(带有 .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'
bash shell unix grep

评论

0赞 Ashok 11/15/2023
可以试试这个sudo -u ${user} sh -c 'cd '${userdirectory}'; find . -type f -iname "*.dat" -o -iname "*.DAT" | sort -u | xargs tree -L 3 -C'
2赞 choroba 11/15/2023
甚至此处突出显示的语法也表明单引号不会嵌套。
0赞 Rubberducky 11/15/2023
谢谢@Ashok。不幸的是,这似乎忽略了树格式的输出:(
0赞 Rubberducky 11/15/2023
谢谢choroba。当我查看我的问题生成的回答时,我才注意到语法突出显示:)

答:

2赞 user1934428 11/15/2023 #1

你的 grep 正则表达式没有多大意义:正则表达式开头的星号具有字面星号的含义,并且仅当生成的文件名之一包含星号时才会匹配。句点与任何字符匹配,因此您基本上搜索子字符串,例如文件名中的 或。如果搜索名称以 结尾的文件,则 grep 表示:findgrep*xdat*%dat.dat[.]dat$

grep -i '[.]dat$'

匹配一个文字点,并将匹配项锚定在行的末尾。[.]$

或者,您可以通过指定 glob 模式来进行选择,find

find .... -iname '*.dat'

或者,如果您确实想使用正则表达式,则通过

find .... -iregex '[.]dat$'

当然,所有这些都要求您的文件名不包含换行符。

在任何情况下,请确保引号正确:如果整个字符串用单引号括起来,则需要对 findgrep 命令的单引号进行转义。

0赞 Paul Hodges 11/17/2023 #2

谁能指出我的代码有什么问题?

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'
  1. 我想你的意思是.sudo -u $user
  2. 修正你的报价。
  3. 修复正则表达式(或其他文件限制方式)。
  4. 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-inamegrep

sudo -u "${user}" sh -c "if cd "${userdirectory}"; then find . -type f -iname '*.dat'; fi" # watch those quotes

顺便说一句,使用正则表达式,而不是 globs。你应该是 - 尽管再次,正如 user1934428 指出的那样,在做这种事情时不要使用,即使你更喜欢正则表达式而不是通配;您仍然可以以大致相同的方式消除额外的过程,但使用 代替 ,如grepgrep -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 有很好的例子和解释。findxargs-exec

...但你不需要树-P'模式。findxargs. 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 中。treeshopt -s nocaseglobtree

这意味着要匹配您可以使用的大写和小写,但这不会匹配名为 的文件,而 -P '*.[分差][aA][tT]'将。相应地选择。-P '*.dat|*.DAT'foo.Dat

-v应该有助于排序。尝试将输出放在所需位置,例如消除输出中没有任何有效命中的目录。--prune--dirsfirst