Bash 如何使用AWK或SED打印第N行之前的字符串并从第N行中删除特定字符串

Bash 如何使用AWK或SED打印第N行之前的字符串并从第N行中删除特定字符串,bash,awk,sed,Bash,Awk,Sed,我有一个由HTML代码组成的文本文件,我需要对其进行操作以提高可读性。我的问题是,每个文件名有两行不是唯一的,但我需要区分它们: 编辑 我将在这里为那些提出请求的人提供输入: <body> <tbody> <tr><td><b>Test Suite</b></td></tr> <tr><td><a href="HAPPY/3_step_minimal_foundation

我有一个由HTML代码组成的文本文件,我需要对其进行操作以提高可读性。我的问题是,每个文件名有两行不是唯一的,但我需要区分它们:

编辑

我将在这里为那些提出请求的人提供输入:

<body>
<tbody>
<tr><td><b>Test Suite</b></td></tr>
<tr><td><a href="HAPPY/3_step_minimal_foundation_no_prefill_HAPPY">3_step_minimal_foundation_no_prefill_HAPPY</a></td></tr>
<tr><td><a href="HAPPY/fullform_no_prefill_HAPPY">fullform_no_prefill_HAPPY</a></td></tr>
<tr><td><a href="HAPPY/fullform_mobile_foundation_no_prefill_HAPPY">fullform_mobile_foundation_no_prefill_HAPPY</a></td></tr>
<tr><td><a href="SAD/3_step_minimal_foundation_SAD">3_step_minimal_foundation_SAD</a></td></tr>
<tr><td><a href="SAD/fullform_SAD">fullform_SAD</a></td></tr>
<tr><td><a href="SAD/fullform_mobile_foundation_SAD">fullform_mobile_foundation_SAD</a></td></tr>
<tr><td><a href="HAPPY_PLUS_OPTIONS/3_step_minimal_foundation_HAPPY_PLUS_OPTIONS">3_step_minimal_foundation_HAPPY_PLUS_OPTIONS</a></td></tr>
<tr><td><a href="HAPPY_PLUS_OPTIONS/fullform_HAPPY_PLUS_OPTIONS">fullform_HAPPY_PLUS_OPTIONS</a></td></tr>
<tr><td><a href="HAPPY_PLUS_OPTIONS/fullform_mobile_foundation_HAPPY_PLUS_OPTIONS">fullform_mobile_foundation_HAPPY_PLUS_OPTIONS</a></td></tr>
<tr><td><a href="SAD_PLUS_OPTIONS/3_step_minimal_foundation_SAD_PLUS_OPTIONS">3_step_minimal_foundation_SAD_PLUS_OPTIONS</a></td></tr>
<tr><td><a href="SAD_PLUS_OPTIONS/fullform_SAD_PLUS_OPTIONS">fullform_SAD_PLUS_OPTIONS</a></td></tr>
<tr><td><a href="SAD_PLUS_OPTIONS/fullform_mobile_foundation_SAD_PLUS_OPTIONS">fullform_mobile_foundation_SAD_PLUS_OPTIONS</a></td></tr>
</tbody></table>
</body>
是否有办法删除/保留编号为N的行中的特定文本?一旦我得到每一行的唯一性,就可以很容易地正确标记每一行

-最好的

去救援

awk 'BEGIN{RS="\n\n"; h="\nFile Name: "}{gsub("_"$3,"",$4); $4=h$4; $5=h$5"\n"; print}'
最后有一个额外的空行。如果重要,您可以使用一些额外的逻辑对其进行修剪,或者简单地将输出管道化到
sed'$d'
,或者
head-n-1

带注释的修订版(thx给Tom Fenech)


没什么大不了的。将记录定义为完整的文本块,而不是每行(这解决了一半问题)。根据您的格式,我们可以通过索引引用各个字段。从一个定义为另一个字段的字段中删除后缀,并准备其他带有标题的字段。

好的,对于与前一行匹配的行,删除从下划线到行尾的所有内容的基本功能,这个过程非常简单。这里有两个选项,100%未经测试

在awk中:

awk '$0 == last { sub(/_[^_]+$/,""); } { last=$0; } 1' inputfile
在壳牌:

while read line; do
    if [ "$line" = "$last" ]; then
        line="${line%_*}"
    fi
    echo "$line"
    last="$line"
done < inputfile
但我们也可以只处理您的原始HTML

在sed中,模式识别非常有趣。以下是GNU sed中的一个:

sed -r 's|<tr><td><a href="([^/]+)/(([^"]+)_[^_]+)".*|Flow Type: \1\nFlow Name: \3\nFile Name: \2|' input.html
或者如果您更喜欢ERE而不是BRE:

<input.html sed -E 's|<tr><td><a href="([^/]+)/(([^"]+)_[^_]+)".*|Flow Type: \1#Flow Name: \3#File Name: \2#|' | tr '#' '\n'

好的,这是我最后一次更新。这就是你要找的吗

awk '
  /<tr><td><a/ {

    type=$0; sub(/^[^"]+"/,"",type); sub(/\/.*/,"",type);
    file=$0; sub(/^[^\/]+\//,"",file); sub(/".*/,"",file);

    if ( index(file, type) ) {
        name=substr(file, 0, index(file, type)-2);
    } else {
        name=file; sub(/_[^_]+$/,"",name);
    }

    printf("Flow type: %s\nFlow name: %s\nFile name: %s\n\n", type, name, file);

  }'
awk'
/ 这可能适用于您(GNU-sed):

使用扩展regexp,不要自动打印每一行。匹配所需字符串并使用反向引用提取所需输出。仅在成功替换时打印

可能适用于其他sed的替代解决方案:

sed -n -e 'G' -e 's/^.*"\([^"\/]*\)\/\(\([^"]*\)_\1\)".*\(.\)/Flow Type: \1\4Flow Name: \3\4File Name: \2\4/p' file
awk'

/您要在此处删除哪些行?目前还不清楚。您尝试将问题分为多个步骤是很好的,但直接从输入到输出可能会更容易。我不尝试删除任何行,我尝试区分两行,这两行对于每个文件都不是唯一的,即(3_step_minimal_foundation_no_prefill_HAPPY和3_step_minimal_foundation_no_prefill_HAPPY)我需要去掉其中一行的_HAPPY,另一行保持不变。我可以添加输入,如果这样可以更容易地编辑好的,现在就可以查看输入了。感谢迄今为止所有的帮助!嗯,现在肯定不容易,所以去做吧,尽你所能添加任何东西。示例输入和预期输出是标准,以及您已经编写的试图实现所做工作的任何代码。如果您能解释您认为代码应该如何工作,那么解决问题的过程会快得多。对于与前一行匹配的行,您是否希望删除从最后一个下划线到行尾的所有内容?而不是将换行符添加到
$5
,我建议在开始时使用块
NR>1{print”“}
。你也可以使用<代码>子<代码>代替<代码> GSUB/COD>。并且可能考虑在字段的结尾添加一个锚点<代码>“$”3美元“$”/代码>。另外,请注意,每个块的第二行前缀与第三行前缀不同。最后,您可以使用
awk-vrs=
一次读取一个块(这样您就可以摆脱
BEGIN
块)。能简单解释一下吗?我试着实现它,但它返回了一个奇怪的格式。文件名有新行:,但其中有两行,实际的流名和文件名不在这些行中。很抱歉,我通知您的信息似乎有点不正确。我的意思是,可以安全地假设我需要在上面所需输出中显示的流名称的HAPPY/SAD/HAPPY\u PLUS\u选项/SAD\u PLUS\u选项之后的文本。真的很抱歉。尽管如此,这确实符合你所说的。谢谢你!在插入每个文件集之间的额外间距之前,是否有一种方法可以从每第三行中剪切一个特定的字符串?完成后,在每一组之间用管道输送额外的管线?这最终摆脱了流动类型:管线。有没有一个小的变化,可以使这些在机智吗?我得到了一个非法的选项-r与该命令。我是否缺少能够使用此功能的模块?我是SED和AWK的新手,所以我道歉。非常感谢你的帮助!啊,你是在使用OSX还是基于BSD的操作系统?如果是,请尝试将
-r
替换为
-E
。较新的BSD添加了
-r
,以便与GNU sed兼容,但在OSX和较旧的变体中
-E
应该实现同样的功能。我正在使用OSX。尝试了上面的SED解决方案,包含HAPPY_PLUS_选项/SAD_PLUS_选项的文件在最后仍然具有HAPPY_PLUS/SAD_PLUS选项。有没有办法从那些需要它的特定行中选择这个字符串并删除它们作为流名称?这与我提出的sed解决方案类似,但正如他在对我的答案的评论中所说的,他在OSX上,没有使用GNU sed.Hmm。不完全是。当你说
$“\n”
你真的想使用bash的特殊引用,比如
$”\n'
?如果是的话,那就添加了一个单独的依赖项。我很想看到使用保留空间来组装行的东西,但是使用
tr
可能会更容易。类似这样的内容:
@ghoti请参阅备选方案的最终修正案。这就是我所说的。你的身体很强壮-D
sed -r 's|<tr><td><a href="([^/]+)/(([^"]+)_[^_]+)".*|Flow Type: \1\nFlow Name: \3\nFile Name: \2|' input.html
<input.html sed -n 's/^.*"\([^"\/]*\)\/\(\([^"]*\)_\1\)".*/Flow Type: \1|Flow Name: \3|File Name: \2|/p'  | tr '|' '\n'`
<input.html sed -E 's|<tr><td><a href="([^/]+)/(([^"]+)_[^_]+)".*|Flow Type: \1#Flow Name: \3#File Name: \2#|' | tr '#' '\n'
awk '
  /<tr><td><a/ {

    type=$0; file=$0;
    sub(/^[^"]+/,"",type); sub(/\/.*/,"",type);
    sub(/^[^\/]+\//,"",file); sub(/".*/,"",file);
    name=file; sub(/_[^_]+$/,"",name);

    printf("Flow type: %s\nFlow name: %s\nFile name: %s\n\n", type, name, file);

  }' input.html
awk '
  /<tr><td><a/ {

    type=$0; sub(/^[^"]+"/,"",type); sub(/\/.*/,"",type);
    file=$0; sub(/^[^\/]+\//,"",file); sub(/".*/,"",file);

    if ( index(file, type) ) {
        name=substr(file, 0, index(file, type)-2);
    } else {
        name=file; sub(/_[^_]+$/,"",name);
    }

    printf("Flow type: %s\nFlow name: %s\nFile name: %s\n\n", type, name, file);

  }'
sed -nr 's/^.*"([^"\/]*)\/(([^"]*)_\1)".*/Flow Type: \1\nFlow Name: \3\nFile Name: \2\n/p' file
sed -n -e 'G' -e 's/^.*"\([^"\/]*\)\/\(\([^"]*\)_\1\)".*\(.\)/Flow Type: \1\4Flow Name: \3\4File Name: \2\4/p' file
awk '
  /<tr><td><a/ {

    type=$0; file=$0;
    sub(/^[^S|^H]+/,"",type); sub(/\/.*/,"",type);
    sub(/^[^\/]+\//,"",file); sub(/".*/,"",file);
    name=file; sub(/_[^fullform|^prefill]+$/,"",name);

    printf("Flow type: %s\nFlow name: %s\nFile name: %s\n\n", type, name, file);

  }’ Filename.txt