虽然读取循环不忽略与 AWK 正在寻找的模式不匹配的文件

while read loop not ignoring files that don't match pattern that awk is looking for

提问人:Rajasekhar 提问时间:8/21/2023 最后编辑:Charles DuffyRajasekhar 更新时间:8/27/2023 访问量:143

问:

从下面的文件中,我只想抓取特殊字符“@”之间的模式。但是,我最终会得到不同的结果。

测试文件:.txt

## START :: start of file ##
[email protected]_path@
#
[email protected]_brkr_path@
#
[email protected]_path@
#
path.mw.site[email protected]_brkr_path@
## END :: end of file ##

文本文件中共有 9 行,我的脚本是test_script.sh

#!/bin/bash
while IFS= read -r line; do
  pattern1=$(echo "$line" | awk -F '@|@' '{print $2}')
  echo $pattern1 one
  
      if [ ! -z "$pattern1" ]; then
       echo "pattern is not empty"
      fi
 
done < "$1"

我添加的第一个 echo 语句,用于测试 pattern1 变量中的值。

raj@my_server ~]$ ./test_script.sh testfile.txt
one
mysite.mw_path one
pattern is not empty
one
mysite.mw_brkr_path one
pattern is not empty
one
mysite.mw_path one
pattern is not empty
one
mysite.mw_brkr_path one
pattern is not empty
one

我得到了上面的输出,我期待如下所示的输出

mysite.mw_path one
pattern is not empty
mysite.mw_brkr_path one
pattern is not empty
mysite.mw_path one
pattern is not empty
mysite.mw_brkr_path one
pattern is not empty

感谢这里的帮助。

提前致谢。

Linux Bash Shell while 循环 脚本

评论

2赞 user1934428 8/21/2023
在你的尝试中,我不明白正则表达式背后的想法。它的意思是 @ 或 @,并且可能更容易写成 。@|@-FS @

答:

3赞 Charles Duffy #1

让一个 awk 副本完成所有工作要合理得多,而不是为每行输入运行一个单独的 awk 副本;您也可以让自己跳过空行:awk

while IFS= read -r pattern1; do
  echo "$pattern1 one"
done < <(awk -F@ '$2 != "" {print $2}')

...它正确地发出:

mysite.mw_path one
mysite.mw_brkr_path one
mysite.mw_path one
mysite.mw_brkr_path one

awk 语句的一般形式是 ;当您跳过 CONDITION 时,它默认对每个输入进行操作,当您跳过 ACTION 时,它默认为 ,但您始终可以同时填写这两个部分。CONDITION { ACTION }print $0

另请注意,这与 完全相同。-F'@|@'-F@

评论

0赞 Rajasekhar 8/21/2023
我还有另一种情况,这里的 testfile1 和 testfile3 是相同的,testfile2 有 2 行 mysite.mw_path=/mw/mysite/cfg/DATA1/ mysite.mw_brkr_path=/usr/local/mw/mysite/cfg/DATA2/ test_script.sh testfile1.txt testfile2.txt sed 仅适用于第 2 行while IFS= read -r line; do pattern1=$(echo "$line" | awk -F '@|@' '{print $2}') if [ -n "$pattern1" ]; then pattern2=$(grep "$pattern1" $2 | awk -F"=" '{ print $2 }') sed "s|$pattern1|$pattern2|g" testfile3.txt > output_21aug.txt fi done < "$1"
1赞 Charles Duffy 8/21/2023
我们回答您提出的问题。如果您有新的和不同的问题,请单独提出。
0赞 Rajasekhar 8/21/2023
@CharlesDuffy - 好的,谢谢
1赞 Jay jargot 8/21/2023 #2

要获得所需的输出,必须将以下行移动到块内if [ -z "$pattern1" ]; then

echo $pattern1 one

建议使用 代替 。printfecho

使用变量时,shell 将执行单词拆分。经常或用于防止这种情况。"${pattern1}""$pattern1"

awk可用于整个文件(编辑):

#!/usr/bin/bash --

while IFS= read -r pattern1 ; do
  if [[ -n "${pattern1}" ]] ; then
    printf "%s one\npattern is not empty\n" "${pattern1}"
  fi
done < <(awk -F '@' '{print $2}' "$1")

评论

0赞 user1934428 8/22/2023
也许更像 bash 的是 ' [ ! -z “${pattern1}” ]'。但你的解决方案当然也是正确的。[[ -n $pattern1 ]]
0赞 Jay jargot 8/22/2023
@user1934428:正确,已修复。感谢。Charles_Duffy提供了性能最高的解决方案。
2赞 user1934428 8/21/2023 #3

我认为为每个输入行启动一个 awk 子进程是矫枉过正的。如果你想读取 bash 中的行,你也可以在 bash 中进行提取。使用变量名称:

 if [[ $line =~ @(.*)@ ]]
 then
   pattern1=${BASH_REMATCH[1]}
   [[ -n $pattern1 ]] && echo pattern is not empty
 else
   echo pattern not found in line "$line"
 fi

评论

0赞 Rajasekhar 8/21/2023
我们如何将文件传递到此处以读取该行?
1赞 Charles Duffy 8/21/2023
考虑修复你的引号 () -- 否则,包含字符串的行将在 的输出中将其替换为与 glob 匹配的文件列表。echo "pattern not found in line $line"*.txtecho
0赞 user1934428 8/21/2023
@Rajasekhar :这是您在原始代码中已有的内容。我没有看到复制这个的理由,只是发布了我的变体来计算。pattern1line
0赞 user1934428 8/21/2023
@CharlesDuffy:对;另外,在不加引号的情况下,会将一连串空格压缩到一个空格中。固定。echo
1赞 knittl 8/21/2023 #4

您既不需要 shell 脚本,也不需要循环。只需使用:cut

cut -sd@ -f2 yourfile.txt

或仅与:awk

awk -F@ '/@/{print $2}'

输出:

mysite.mw_path
mysite.mw_brkr_path
mysite.mw_path
mysite.mw_brkr_path

如果你还想用 shell 循环解决问题,你可以直接在 shell 中完成(无需每次都生成进程):awk

#!/bin/sh
while IFS=@ read -r _ pattern1 _; do
  if [ -n "$pattern1" ]; then
    echo "$pattern1 one"
    echo "pattern is not empty"
  fi
done < "$1"

(并且没有必要运行它bash)

评论

0赞 Rajasekhar 8/21/2023
-谢谢你,请在这里帮忙,实际上我问的问题是这个问题的子集,这里是这种情况,这里的 testfile1 和 testfile3 是相同的,testfile2 有 2 行(键值对) mysite.mw_path=/mw/mysite/cfg/DATA1/ mysite.mw_brkr_path=/usr/local/mw/mysite/cfg/DATA2/ test_script.sh testfile1.txt testfile2.txt sed 仅适用于第 2 行while IFS=@ read -r _ pattern1 _; do if [ -n "$pattern1" ]; then pattern2=$(grep "$pattern1" $2 | awk -F"=" '{ print $2 }') sed "s|$pattern1|$pattern2|g" testfile3.txt > output_21aug.txt fi done < "$1"
0赞 knittl 8/21/2023
@Rajasekhar无法阅读评论中发布的代码。如果您有后续问题,请发布一个新问题(并链接现有问题)。shell 脚本可能不是解决您的问题的最佳或最简单的解决方案。您是否考虑过使用 python 或 perl 脚本?
0赞 RARE Kpop Manifesto 8/24/2023 #5
echo '
## START :: start of file ##
[email protected]_path@
#
[email protected]_brkr_path@
#
[email protected]_path@
#
path.mw.site.[email protected]_brkr_path@
## END :: end of file ##'

awk '_<($!NF = $2)' FS='@'

mysite.mw_path
mysite.mw_brkr_path
mysite.mw_path
mysite.mw_brkr_path