我有一个 bash 脚本,它应该遍历所有文件名并仅打印包含特定字母的文件名(假设它是“o”)。
我做了什么:
command=`ls -l`
for file in $command
do
if $file | grep 'o' ;
then
echo "$file"
fi
done
这不起作用,它在线上显示“未找到命令”:
if $file | grep 'o' ;
我在这里查找了其他几个答案,他们正在做与我相同的事情,即 if 语句没有括号,语法相同等。
我在忽略什么?
答案1
$file | grep -o
file
执行由和 的值指定的命令管道其输出到grep
.但这显然不是你想要的。
如果您想列出包含以下内容的文件o
您的意思是 的值file
是 的输入文件grep
,而不是要执行的命令。所以你需要一个输入重定向,不是管道。
if grep 'o' <"$file"
grep
如果在命令行上没有收到文件名,则从标准输入读取。您还可以在命令行上传递文件名;这做同样的事情。
if grep 'o' -- "$file"
有关为什么使用双引号以及为什么--
在第二种方法中,请参阅为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?
要抑制 的输出grep
,请使用-q
选项,或将输出重定向到/dev/null
。
if grep -q 'o' <"$file"
或者
if grep 'o' <"$file" >/dev/null
脚本的另一个问题是将command=`ls -l`
变量设置command
为命令的输出ls -l
,这不是文件名列表。如果你还记得为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?,你会记得不可能存储列表a 中的文件名细绳变量:所有文件名都混在一起。在这里,情况更糟:存在权限、日期等垃圾。在 shell 脚本中获取文件名列表的方法是使用通配符模式。
for file in *
do
if grep -q 'o' <"$file"
then
echo "$file"
fi
done
所有这些都相当于
grep -l 'o' -- *
如果要列出名称包含以下内容的文件o
该功能内置于 shell 中,具有通配符模式。该模式*o*
匹配包含 的文件名o
,因此要列出它们,您只需要
ls -l -- *o*
--
如果文件名之一以 开头,则这是必需的-
,否则ls
可能会将文件名解释为选项。
如果这是关于使用 的学习练习grep
,并且您想要将文件名作为输入传递给grep
,则需要使用该echo
命令。
echo "$file" | grep 'o'
该echo
命令可能会破坏某些文件名。为了安全起见,请使用printf
.有关此内容以及双引号的使用的更多信息,请参阅为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?
printf '%s\n' "$file" | grep 'o'
如上所述,不解析 的输出ls
。
for file in *
do
if printf '%s\n' "$file" | grep -q 'o'
then
printf '%s\n'
fi
done
如果您的文件名不包含任何换行符,您可以将其减少为。
for file in *
do
printf '%s\n' "$file" | grep 'o'
done
再说一次,循环在这里毫无意义,你可以使用
printf '%s\n' *o*
将匹配的文件名打印在单独的行上。grep
仅当您需要一个正则表达式,而您的 shell 的通配符模式不足以表达时,才需要使用。
答案2
你正在尝试执行$file
.相反,你必须回显它:
# ...
if echo "$file" | grep 'o' ;
# ...
请注意,grep 已经打印了文件名,因此您应该将其静音(例如grep -q 'o'
或grep 'o' >/dev/null
)。
你也传递-l
到ls
,你不想做。ls -l
打印文件名和属性,您将与它们进行匹配。
另外,如果您希望它适用于任何文件,您可能需要使用引号,但这不是问题的根源。
PS:正如其他人指出的那样,您ls
一开始就不应该使用。
答案3
ls
您根本不应该依赖输出。ls
旨在显示人类友好的输出,而不是在脚本中使用。请参阅以下示例;
for f in ./*
do
if [[ $f = *o* ]]; then
printf '%s\n' "$f"
fi
done
答案4
首先,这不是将某些内容通过管道传递给 grep 的方式。还有,它是一般来说被认为是将命令与条件分开并仅检查返回码的更好形式。
像下面这样的东西完美地工作:
command=`ls -l`
for file in "$command"
do
echo "$file" | grep 'o'
if [ $? -eq 0 ]; then
echo "$file"
fi
done