嗨我的工作命令是:
grep -l "my text" file*.ext|xargs ls -lart
这个命令对我来说非常有用,我想创建一个 shell 文件,用更少的输入来完成它,如下所示:
fn "my text" file*.ext
我来到这个shell脚本文件:
grep -l "$1" "$2"|xargs ls -lart
这不起作用,甚至第一部分也不起作用:
grep -l "$1" "$2"
返回 null
答案1
您的脚本需要采用两个以上的参数。
在shell执行grep
命令之前
grep -l "my text" file*.ext
文件名通配模式file*.ext
扩展到所有匹配的文件名。因此最终运行的命令行将是
grep -l "my text" file1.ext file2.ext file3.ext
(如果这些是与模式匹配的文件)
因此,您的脚本可能看起来像
#!/bin/sh
pattern=$1
shift
grep -l -e "$pattern" "$@" | xargs ls -lrt
在这里,模式被保存到一个变量中,然后从命令行参数列表中移出。其余参数是文件名列表(如果命令行上的文件名通配模式匹配)并且可在"$@"
.
确保双引号$@
。这将$@
扩展到单独引用的命令行参数的列表。
我已删除该-a
选项,ls
因为在提供要列出的显式文件名时不需要它。我还使用grep
with-e
来指定模式,因为带有初始破折号 ( -
) 的模式可能会造成混淆grep
。
如果不是为了排序,我会建议使用以下find
命令而不是管道(正确处理带有空格和换行符的文件名):
find . -type f -name "$filepattern" -exec grep -q -e "$pattern" {} ';' -ls
这会查找名称与 中的内容匹配$filepattern
、内容与 中的内容匹配的文件$pattern
,然后生成ls -l
类似的输出。搜索在当前目录中递归执行。
作为脚本的一部分:
#!/bin/sh
pattern=$1
filepattern=$2
find . -type f -name "$filepattern" -exec grep -q -e "$pattern" {} ';' -ls
这脚本需要以这样的方式调用:在调用它时,shell 不会扩展文件名通配模式:
$ ./script.sh 'my text' 'file*.ext'
答案2
为了使其更安全,尽管依赖 GNU 扩展:
#! /bin/sh -
pattern=${1?pattern required}; shift
: "${1?no filename specified}"
grep -l --null -e "$pattern" -- "$@" |
xargs -r0 ls -lrtd --
使用--null
/ -0
,我们可以避免包含空格、引号或反斜杠的文件名出现问题。
这样-e "$pattern"
,我们就可以避免以 开头的模式出现问题-
。
使用--
,我们可以避免以 . 开头的文件名出现问题-
。
使用-d
,我们可以避免目录类型的文件恰好匹配时可能出现的混淆。
使用-r
,如果没有匹配的文件,我们可以避免列出当前目录。
请注意,对于大量文件,可能会选择对部分文件列表xargs
运行多次调用,这意味着输出将无法按时间正确列出。ls
另请注意,这-
意味着 stdin 为,但在当前目录中grep
调用的文件为。 GNU将输出(或其翻译成您的语言)。如果要指定当前目录中调用的文件,请使用.-
ls
grep -l
(standard input)
-
./-
-