如何使用 Bash 测试文件中是不是存在字符串?

Posted

技术标签:

【中文标题】如何使用 Bash 测试文件中是不是存在字符串?【英文标题】:How to test if string exists in file with Bash?如何使用 Bash 测试文件中是否存在字符串? 【发布时间】:2011-06-12 13:39:51 【问题描述】:

我有一个包含目录名称的文件:

my_list.txt

/tmp
/var/tmp

如果文件中已存在目录名称,我想先签入 Bash,然后再添加目录名称。

【问题讨论】:

要查找文件中的所有字符串,可以在 FOR 循环中运行 grep:unix.stackexchange.com/a/462445/43233 【参考方案1】:
grep -Fxq "$FILENAME" my_list.txt

如果找到名称,则退出状态为 0(真),否则为 1(假),所以:

if grep -Fxq "$FILENAME" my_list.txt
then
    # code if found
else
    # code if not found
fi

说明

这里是the man page for grep的相关部分:

grep [options] PATTERN [FILE...]

-F, --fixed-strings

        将 PATTERN 解释为固定字符串的列表,由换行符分隔,其中任何一个都将被匹配。

-x, --line-regexp

        只选择与整行完全匹配的匹配项。

-q--quiet--silent

        安静;不要向标准输出写入任何内容。如果找到任何匹配项,即使检测到错误,也会立即以零状态退出。另请参阅 -s--no-messages 选项。

错误处理

正如在 cmets 中正确指出的那样,上述方法会默默地处理错误情况,就好像找到了字符串一样。如果您想以不同的方式处理错误,则必须省略 -q 选项,并根据退出状态检测错误:

通常,如果找到选定的行,则退出状态为 0,否则为 1。但如果发生错误,则退出状态为 2,除非使用 -q--quiet--silent 选项并找到选定的行。但是请注意,POSIX 仅要求对于诸如grepcmpdiff 之类的程序,出现错误时的退出状态大于1;因此,为了可移植性,建议使用测试此一般条件的逻辑而不是与 2 严格相等。

要抑制来自grep 的正常输出,您可以将其重定向到/dev/null。请注意,标准错误仍然是无向的,因此grep 可能打印的任何错误消息都将按照您可能想要的方式在控制台上结束。

要处理这三种情况,我们可以使用case 语句:

case `grep -Fx "$FILENAME" "$LIST" >/dev/null; echo $?` in
  0)
    # code if found
    ;;
  1)
    # code if not found
    ;;
  *)
    # code if an error occurred
    ;;
esac

【讨论】:

如果我从 bash 脚本执行此命令,如何将 0 或 1 捕获到变量中? @Toren 可以使用$? 访问最近的退出状态。您还可以在 if 语句旁边使用 grep 命令(如更新的答案所示)。 您可以使用grep -Fqx "$FILENAME",您不必担心变量内容中的正则表达式字符,也不必在搜索字符串中使用它们。 @Toren:如果没有-F,您的文件名将被解释为正则表达式,而不是普通字符串。因此,如果它包含奇怪的字符(如.),它们将被grep 的正则表达式引擎解释,而不是字面匹配。 -x 标志确保字符串匹配整行,而不仅仅是其中的一部分:因此,如果您搜索 foo,则仅匹配完全包含 foo 的行,而不是 foobar。 (我的示例中有一个错误;它仍然使用一些正则表达式语法。现在已修复。) 对于查看此答案的人们的几点说明:1) 在 bash 中,0 始终为真,其他任何内容始终为假 2) 如果您希望整行匹配,请仅使用 -x 标志确切地。如果您只是想查找您的字符串是否存在于文件中,请将其关闭。如果您想查找您的字符串是否完全存在但不一定匹配整行(即作为一个完整的单词),请使用 -w。【参考方案2】:

关于以下解决方案:

grep -Fxq "$FILENAME" my_list.txt

如果您想知道(和我一样)-Fxq 在简单的英语中是什么意思:

F:影响 PATTERN 的解释方式(固定字符串而不是正则表达式) x: 匹配整行 q: 嘘……最少打印

来自 man 文件:

-F, --fixed-strings
    Interpret  PATTERN  as  a  list of fixed strings, separated by newlines, any of which is to be matched.
    (-F is specified by POSIX.)
-x, --line-regexp
    Select only those matches that exactly match the whole line.  (-x is specified by POSIX.)
-q, --quiet, --silent
    Quiet; do not write anything to standard output.  Exit immediately with zero status  if  any  match  is
          found,  even  if  an error was detected.  Also see the -s or --no-messages option.  (-q is specified by
          POSIX.)

【讨论】:

-F 不会影响文件处理,它会影响 PATTERN 的解释方式。通常,PATTERN 被解释为正则表达式,但使用 -F 将被解释为固定字符串。【参考方案3】:

我心目中的三种方法:

1) 路径中名称的简短测试(我不确定这可能是您的情况)

ls -a "path" | grep "name"

2) 对文件中的字符串进行简短测试

grep -R "string" "filepath"

3) 使用正则表达式的更长的 bash 脚本:

#!/bin/bash

declare file="content.txt"
declare regex="\s+string\s+"

declare file_content=$( cat "$file" )
if [[ " $file_content " =~ $regex ]] # please note the space before and after the file content
    then
        echo "found"
    else
        echo "not found"
fi

exit

如果您要使用循环测试文件上的多个字符串内容(例如在任何 cicle 处更改正则表达式),这应该会更快

【讨论】:

为什么$file_contenet前后需要空格? 加 1 用于快速解决方案和更通用的解决方案 =~ 是什么,在哪里可以了解更多信息?【参考方案4】:

最简单的方法是:

isInFile=$(cat file.txt | grep -c "string")


if [ $isInFile -eq 0 ]; then
   #string not contained in file
else
   #string is in file at least once
fi

grep -c 将返回字符串在文件中出现的次数。

【讨论】:

【参考方案5】:

更简单的方法:

if grep "$filename" my_list.txt > /dev/null
then
   ... found
else
   ... not found
fi

提示:如果您想要命令的退出状态而不是输出,请发送至/dev/null

【讨论】:

或使用-q--quiet 相同:) 同意-q 也是最佳答案,排名第四。这个世界上没有正义。【参考方案6】:

如果我正确理解了您的问题,这应该可以满足您的需要。

    您可以通过 $check 变量指定要添加的目录 如果该目录已经在列表中,则输出为“目录已列出” 如果目录尚未在列表中,则将其附加到 my_list.txt

一行check="/tmp/newdirectory"; [[ -n $(grep "^$check\$" my_list.txt) ]] && echo "dir already listed" || echo "$check" >> my_list.txt

【讨论】:

您不需要测试 grep 的输出,您可以使用 grep -q 并直接从 if 调用 grep,就像 Thomas 在他的回答中所做的那样。此外,问题不包括在将目录添加到列表之前检查目录是否存在(毕竟它可能是已删除目录的列表)。 我删除了示例脚本,它没有为 Thomas 给出的答案添加任何内容。【参考方案7】:
grep -E "(string)" /path/to/file || echo "no match found"

-E 选项让 grep 使用正则表达式

【讨论】:

【参考方案8】:

@Thomas 的解决方案由于某种原因对我不起作用,但我的字符串较长,带有特殊字符和空格,所以我只是更改了如下参数:

if grep -Fxq 'string you want to find' "/path/to/file"; then
    echo "Found"
else
    echo "Not found"
fi

希望对某人有所帮助

【讨论】:

【参考方案9】:

这是搜索和评估字符串或部分字符串的快速方法:

if grep -R "my-search-string" /my/file.ext
then
    # string exists
else
    # string not found
fi

您也可以先测试,如果该命令仅通过运行返回任何结果:

grep -R "my-search-string" /my/file.ext

【讨论】:

我建议添加 -q 这样您就不会在标准输出中找到找到的字符串【参考方案10】:

如果只想检查一行是否存在,则不需要创建文件。例如,

if grep -xq "LINE_TO_BE_MATCHED" FILE_TO_LOOK_IN ; then
  # code for if it exists
else
  # code for if it does not exist
fi  

【讨论】:

【参考方案11】:

我使用 fgrep 的版本

  FOUND=`fgrep -c "FOUND" $VALIDATION_FILE`
  if [ $FOUND -eq 0 ]; then
    echo "Not able to find"
  else
    echo "able to find"     
  fi  

【讨论】:

我在fgrep --help 中没有看到-c 选项【参考方案12】:

我正在寻找一种在终端中执行此操作的方法,并以正常的“grep 行为”过滤行。将您的字符串保存在 strings.txt 文件中:

string1
string2
...

然后你可以构建一个像(string1|string2|...)这样的正则表达式并使用它进行过滤:

cmd1 | grep -P "($(cat strings.txt | tr '\n' '|' | head -c -1))" | cmd2

编辑:以上仅在您不使用任何正则表达式字符时有效,如果需要转义,可以这样做:

cat strings.txt | python3 -c "import re, sys; [sys.stdout.write(re.escape(line[:-1]) + '\n') for line in sys.stdin]" | ...

【讨论】:

【参考方案13】:

一个无 grep 的解决方案,对我有用:

MY_LIST=$( cat /path/to/my_list.txt )



if [[ "$MY_LIST" == *"$NEW_DIRECTORY_NAME"* ]]; then
  echo "It's there!"
else
echo "its not there"
fi

基于: https://***.com/a/229606/3306354

【讨论】:

在文件很大的情况下使用过多的内存。 accepted answer 中描述的grep -q 是最有效的方法。【参考方案14】:
grep -Fxq "String to be found" | ls -a
grep 会帮你检查内容 ls 将列出所有文件

【讨论】:

@ThomWiggers 我尝试了同样的方法,它对我有用。【参考方案15】:

与其他答案略有相似,但不分叉 cat 并且条目可以包含空格

contains() 
    [[ " $list[@] " =~ " $1 " ]] && echo 'contains' || echo 'does not contain'


IFS=$'\r\n' list=($(<my_list.txt))

所以,my_list.txt 喜欢

/tmp
/var/tmp
/Users/usr/dir with spaces

这些测试

contains '/tmp'
contains '/bin'
contains '/var/tmp'
contains '/Users/usr/dir with spaces'
contains 'dir with spaces'

返回

exists
does not exist
exists
exists
does not exist

【讨论】:

【参考方案16】:
if grep -q "$Filename$" my_list.txt
   then
     echo "exist"
else 
     echo "not exist"
fi

【讨论】:

以上是关于如何使用 Bash 测试文件中是不是存在字符串?的主要内容,如果未能解决你的问题,请参考以下文章

第五课-第三讲05_03_bash脚本编程之二 条件判断

测试 glob 在 Bash 中是不是有任何匹配项

如何在 bash 脚本中使用正则表达式否定测试?

如何使用 Bash 检查文件是不是包含特定字符串

bash,测试curl是不是存在,如果不存在则安装[重复]

bash脚本编程基础