如何使用grep命令将字符串搜索放入if语句?


11

我想在两个文件中搜索多个字符串。如果在两个文件中都找到一个字符串,则进行处理。如果仅在一个文件中找到一个字符串,则进行另一件事。

接下来是我的命令:

####This is for the affirmative sentence in both files
if grep -qw "$users" "$file1" && grep -qw "$users" "$file2"; then

####This is for the affirmative sentence in only one file, and negative for the other one
if grep -qw "$users" "$file1" ! grep -qw "$users" "$file2"; then

否定和确认声明的正确方法吗?pd我正在使用KSH shell。

先感谢您。

Answers:


11

尝试这个:

if grep -wq -- "$user" "$file1" && grep -wq -- "$user" "$file2" ; then
   echo "string avail in both files"
elif grep -wq -- "$user" "$file1" "$file2"; then
   echo "string avail in only one file"
fi
  • grep 可以在多个文件中搜索模式,因此无需使用OR / NOT运算符。

每个命令中的“ -wq”和“ -qw”之间是否存在最小差异?
Mareyes

2
不,它们都为grep提供-q和-w选项。
格伦·杰克曼

3
为什么在变量扩展中没有引号?
D. Ben Knoble

@ D.BenKnoble是否正确:“ $ user”“ $ file1”?
Mareyes

1
@Mareyes是的,没错
D. Ben Knoble

13

另外一个选项:

grep -qw -- "$users" "$file1"; in_file1=$?
grep -qw -- "$users" "$file2"; in_file2=$?

case "${in_file1},${in_file2}" in
    0,0) echo found in both files ;;
    0,*) echo only in file1 ;;
    *,0) echo only in file2 ;;
      *) echo in neither file ;;
esac

嘿,谢谢您的可选方式。它足够好用!!在我拥有的另一个脚本中可以完美工作。
Mareyes

好主意啊!总是学习。

7
n=0

#Or if you have more files to check, you can put your while here. 
grep -qw -- "$users" "$file1" && ((n++))
grep -qw -- "$users" "$file2" && ((n++))

case $n in 
   1) 
       echo "Only one file with the string"
    ;;
   2)
       echo "The two files are with the string"
   ;;
   0)
       echo "No one file with the string"
   ;;
   *)
       echo "Strange..."
   ;;
esac 

注:((n++))是KSH扩展(也支持zshbash)。在POSIX sh语法中,您需要n=$((n + 1))代替。


抱歉,我正在输入$(((n ++))而不是((n ++)))。忘记。
Luciano Andress Martini

1
注意,n=$((n++))永远不要更改n的值,因为它n++递增的:它返回n 的当前值,然后递增n;否则返回n。然后将变量设置为返回值,即原始n。
格伦·杰克曼

如果可以假设文件名不包含换行符,请local IFS=$'\n'; matches=( $(grep -lw "$users" "$file1" "$file2") )使用case "${#matches[@]" in。@glenn:这个想法也适用于您的答案,以避免多次调用grep。用管道连接grep -l | wc -l也可以。
彼得·科德斯

@Peter值得单独写为IMO。
斯蒂芬·基特

@StephenKitt:我不想这么做,因为我找不到处理任何文件名字符的防弹方法。但是既然您认为值得,我还是把它写下来了。
彼得·科德斯

2

如果文件名不包含换行符,则可以grep通过让grep打印匹配文件的名称并计算结果来避免多次调用。

 local IFS=$'\n'    # inside a function.  Otherwise use some other way to save/restore IFS
 matches=( $(grep -lw "$users" "$file1" "$file2") )

比赛次数是"${#matches[@]}"

这里可能有一种使用方法grep --null -lw,但是我不确定如何解析输出。Bash var=( array elements )无法使用\0定界符代替\n。也许bash的mapfile内置功能可以做到吗?但可能不是,因为您使用指定了分隔符-d string


可以count=$(grep -l | wc -l),但是您有两个外部进程,因此您最好grep分别在两个文件上运行。(相比于用fork + exec +动态链接器来启动一个单独的进程,启动开销grepwc启动开销之间的差异很小)。

另外,与wc -l你没有发现哪个文件相匹配。


将结果捕获在数组中后,可能已经是您想要的结果,或者如果存在完全匹配的1个匹配项,则可以检查它是否是第一个输入。

local IFS=$'\n'    # inside a function.  Otherwise use some other way to save/restore IFS
matches=( $(grep -lw "$users" "$file1" "$file2") )

# print the matching filenames
[[ -n $matches ]] && printf  'match in %s\n'  "${matches[@]}"

# figure out which input position the name came from, if there's exactly 1.
if [[ "${#matches[@]" -eq 1 ]]; then
    if [[ $matches == "$file1" ]];then
        echo "match in file1"
    else
        echo "match in file2"
    fi
fi

$matches${matches[0]}第一个数组元素的缩写。


@StephenKitt:我的意思-z不是-0,哎呀。是的,这会使grep打印出文件名,\0就像我在答案中已经提到的那样,用分隔开的文件名,但是如何使bash解析出来呢?您不能设置IFS=$'\0',或者基本上不能find -print0直接使用bash 使用样式输出进行其他操作。
彼得·科德斯

是的,我读得太快了,错过了该段,也没有考虑透彻(这就是为什么我删除了评论)。也许有一种方法,但是我暂时想不出一种方法,正如您所说,当仅需grep处理几个问题时,将解决方案变得过于复杂是不值得的。
史蒂芬·基特

1
mapfile -d $'\0'的作品,但它用空格代替换行符(我没有尝试过调整IFS)。
史蒂芬·基特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.