在文件中搜索子字符串匹配 bash

Search for substring matches in a file bash

前提是要存储一个由冒号分隔的值代表项目的数据库文件。

var1:var2:var3:var4

我需要对该文件进行排序并提取任何值与搜索字符串匹配的行。 例如

Search for "Help"
Hey:There:You:Friends
I:Kinda:Need:Help (this line would be extracted)

我正在使用一个函数来传递搜索字符串,然后将找到的行传递给另一个函数来格式化输出。但是,我似乎无法在通过时获得正确的格式。这是我尝试过的示例代码,我在这个网站上找到了不同的方法,但它们似乎对我不起作用

#Option 1, it doesn't ever find matches
function retrieveMatch {
  if [ -n "" ]; then
    while read line; do
      if [[ *""* =~ "$line" ]]; then
        formatPrint "$line"
      fi
    done
  fi
}

#Option 2, it gets all the matches, but then passes the value in a
#format different than a file? At least it seems to...
function retrieveMatch {
  if [ -n "" ]; then
    formatPrint `cat database.txt | grep ""`
  fi
}

function formatPrint {
  list="database.txt" #default file for printing all info
  if [ -n "" ]; then
    list=""
  fi
  IFS=':'
  while read var1 var2 var3 var4; do
    echo "$var1"
    echo "$var2"
    echo "$var3"
    echo "$var4"
  done < "$list"
}

我似乎无法让第一个找到任何匹配项 第二个选项获得了正确的值,但是当我尝试格式化打印时,它抛出一个错误,指出传入的值列表不是目录。

我觉得我一定错过了什么,但是..

cat > foo.txt
Hey:There:You:Friends I:Kinda:Need:Help
Foo:Bar

[控制-D]

grep -i help foo.txt
Hey:There:You:Friends I:Kinda:Need:Help

符合要求吗?

编辑:进一步扩展这个想法..

cat > foo.bsh
#!/bin/bash
hits="$(grep -i help foo.txt)"
while read -r line; do
    echo "${line}"
done <<< "$hits"

[控制-D]

老实说,我会将整个内容替换为

function retrieveMatch {
  grep "" | tr ':' '\n'
}

被称为

retrieveMatch Help < filename

...像原来的功能(选项1)似乎是设计出来的。要用匹配行做更复杂的事情,看看 awk:

# in the awk script, the fields in the line will be ,  etc.
awk -v pattern="" -F : '[=12=] ~ pattern { for(i = 1; i < NF; ++i) print $i }'

参见 this link。 awk 就是用来处理这类数据的,所以如果你打算用它做复杂的事情,它绝对值得一看。

更直接地回答问题,您的代码中存在 two/three 个问题。一个是,正如在对该问题的评论中指出的那样,

if [[ *""* =~ "$line" ]]; then

将尝试使用 "$line" 作为正则表达式在 *""* 中查找匹配项,假设 *""* 在路径名扩展后不会变成多个标记,因为 * 没有被引用。假设 * 应该按照它们在 glob 表达式中的方式匹配任何内容(但不是在正则表达式中),这可以替换为

if [[ "$line" =~ "" ]]; then

因为如果正则表达式匹配字符串的任何部分,=~ 将报告匹配。

第二个问题是您在 formatPrint 中的 "$list" 是一个文件还是一行的问题上存在分歧。你在retrieveMatch中说应该是一行:

formatPrint "$line"

但是你在formatPrint中将其设置为默认文件名:

list="database.txt" #default file for printing all info

你必须决定一个。如果您决定 formatPrint 应该格式化行,那么第三个问题是

中的重定向
while read var1 var2 var3 var4; do
  echo "$var1"
  echo "$var2"
  echo "$var3"
  echo "$var4"
done < "$list"

尝试使用 "$list" 作为文件名。这可以通过将最后一行替换为

来解决
done <<< "$list" # using a here-string (bash-specific)

或者

done <<EOF
$list
EOF

(注意:在后一种情况下,不要缩进代码;它是逐字记录的此处文档)。当然,read 只会按照您编写的方式拆分四个字段。