我想检查文件 /etc/passwd 的哪些行以“/bin/bash”字符串(字段编号 7,“:”作为分隔符)结尾。 到目前为止,我已经编写了以下代码:
while read line
do
if [ $("$line" | cut -d : -f 7)=="/bin/bash" ]
then
echo $line | cut -d : -f 1
echo "\n"
fi
done < /etc/passwd
目前,执行脚本会引发错误,显示错误解释(很可能是由于语法)。 如果您能帮助我,我将不胜感激。
答案 0 :(得分:1)
您必须用空格将 ==
运算符括起来。 [
和 [[
根据给定的参数数量做不同的事情:
if [ "$( echo "$line" | cut -d: -f7 )" == "/bin/bash" ]; ...
我实际上会这样做:在您阅读该行时将其解析为字段。
while IFS=: read -ra fields; do
[[ ${fields[-1]} == "/bin/bash" ]] && printf "%s\n\n" "${fields[0]}"
done < /etc/passwd
答案 1 :(得分:0)
与其循环遍历行,然后检查 /bin/bash
部分,不如使用类似 grep 之类的东西来获取所有所需的行,如下所示:
grep ':/bin/bash$' /etc/passwd
可选性,您可以使用 simple while
循环遍历行;
grep ':/bin/bash$' /etc/passwd | while read -r line ; do
echo "Processing $line"
done
答案 2 :(得分:0)
不要做while read | cut
。将 IFS 用作:
#!/bin/sh
while IFS=: read name passwd uid gid gecos home shell; do
if test "$shell" = /bin/bash; then
echo "$name"
fi
done < /etc/passwd
但是对于这个特定的用例,最好这样做:
awk '$7 == "/bin/bash"{print $1}' FS=: /etc/passwd
您的代码存在的问题是一个常见错误。考虑这一行:
if [ $("$line" | cut -d : -f 7)=="/bin/bash" ]
假设您在 $line
中有一个值,其中最后一个字段是 /bin/dash
。进程替换将插入字符串 /bin/dash
,bash 将尝试执行:
if [ /bin/dash==/bin/bash ]
由于 /bin/bash==/bin/bash
是一个非空字符串,命令 [ /bin/bash==/bin/bash ]
成功返回。它不执行任何类型的字符串比较。为了让 [
进行字符串比较,您需要向它传递 4 个参数。例如,[ /bin/dash = /bin/bash ]
会失败。请注意,该调用的 4 个参数是 /bin/dash
、=
、/bin/bash
和 ]
。 [
是一个非常奇怪的命令,需要它的最后一个参数是 ]
。我强烈建议永远不要使用它,而是用它的表亲 test
(非常密切相关,实际上 test
和 [
曾经链接到同一个可执行文件)替换它,它的行为与相同但不要求其最终参数为 ]
。
答案 3 :(得分:0)
这一行是错误的:
if [ $("$line" | cut -d : -f 7)=="/bin/bash" ]
另外,这不会做你想做的:
echo "\n"
Bash echo 不理解反斜杠转义字符
-e.如果您想打印一个新行,只需使用 echo
但请注意
之前的回声:
echo $line | cut -d : -f 1
将添加一个换行符。
你应该经常检查你的脚本 shellcheck。正确的脚本是:
#!/usr/bin/env bash
while read -r line
do
if [ "$(echo "$line" | cut -d : -f 7)" == "/bin/bash" ]
then
echo "$line" | cut -d : -f 1
fi
done < /etc/passwd
但是请注意,您实际上并不需要一个非常缓慢且 可以使用以下 awk one-liner:
awk -v FS=: '$7 == "/bin/bash" {print $1}' /etc/passwd