unix 与指定的模式不匹配的文件通过find返回

hjzp0vay  于 6个月前  发布在  Unix
关注(0)|答案(2)|浏览(104)

我的目的是显示目录和文件(只有在树结构中才有.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'
s4n0splo

s4n0splo1#

你的grep regex没有多大意义:正则表达式开头的星号具有字面星号的含义,并且仅当find生成的文件名中包含星号时才匹配。句点匹配任何字符,因此,grep基本上是在文件名中搜索子字符串,如*xdat*%dat。如果搜索文件名以.dat,grep for [.]dat$

grep -i '[.]dat$'

字符串
[.]匹配文字点,$将匹配锚定在行尾。
或者,您可以让find进行选择,通过指定一个glob模式,

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


或者如果你想使用正则表达式,

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


当然,所有这些都要求你的文件名不包含换行符。
在任何情况下,都要确保引号是正确的:如果整个字符串都用单引号括起来,则需要对 findgrep 命令的单引号进行转义。

erhoui1w

erhoui1w2#

有谁能告诉我我的代码有什么问题吗?
tree需要 directories,所以你的基本前提被打破了。
你不能用这种方式在一个特定的 file 参数列表上调用它,但是看起来你真正需要的只是-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

字符串
(The -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
1.修正你的引用。
1.修复正则表达式(或其他文件限制方法)。

  1. 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;"


这将传递单引号以保护${userdirectory}中的任何嵌入空格,但仍将在将整个内容传递给sudo之前插入${userdirectory}的 * 值 * 作为
请注意,如前所述,如果cd失败,它将执行任何剩余的命令,无论它在哪里。通常,如果可能的话,最好检查一下。例如,

sudo -u "${user}" sh -c "if cd '${userdirectory}'; then : do stuff; else echo aborting; fi"


给定的find将返回当前目录下的所有普通文件。正如user 1934428所指出的,-iname将允许您返回不区分大小写的匹配,无需单独的grep

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


顺便说一句,grep使用的是正则表达式,而不是globs。你的grep -i '*.dat'应该是grep -i '\.dat$'--尽管如此,正如user 1934428所指出的,在做这类事情时不要使用grep,即使你更喜欢正则表达式而不是globbing;您仍然可以以相同的方式消除额外的进程,但使用-iregex '[.]dat$'而不是-iname '*.dat',如

sudo -u "${user}" sh -c "if cd "${userdirectory}"; then find . -type f -iregex '[.]dat$'; fi"


通过一个简单的词法sort传递也可能不会达到您想要的效果,但是如果您搜索的话,这确实是另一个广泛存在的讨论。
正如我们上面提到的,find根本不是你所需要的,所以xargs也变得多余了(更不用说-exec了)。如果你正在做一些有用的事情,请参考BashFAQ #20,这里有很好的例子和解释。
.但你不需要find * 或 * xargs. Just callwith the-P`模式。

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"


要知道tree是“globbing”,所以它不是一个真实的正则表达式,但是它也可能没有shell提供的所有功能。例如,设置shopt -s nocaseglob似乎不起作用,因为它可能没有复制到tree的子shell中。
这意味着要同时匹配大小写,您可以使用-P '*.dat|*.DAT',但这不会匹配名为foo.Dat的文件,而-P '*.[dD][aA][tT]'可以。相应地选择。
-v应该有助于排序。使用--prune--dirsfirst可以在您想要的位置获得输出,例如消除输出中没有任何有效命中的目录。

相关问题