![](/img/trans.png)
[英]How to extra top n lines from a multi line string in bash (sed/awk/??)
[英]How to print a string before line N and delete specific string from line N using AWK or SED
我有一個包含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>
3_step_minimal_foundation_no_prefill_HAPPY
和
3_step_minimal_foundation_no_prefill_HAPPY
例如需要成為:
3_step_minimal_foundation_no_prefill
和
3_step_minimal_foundation_no_prefill_HAPPY
我當前的文本文件狀態:
這是我實現此目的的代碼:
$ sed -n '/ref/p' EVERYTHING | awk -F'[/"<> ]+' '{sub("", "", $6); print $6, $7, $8}' | tr -s '[[:space:]]' '\n' | awk -v n=3 '1; NR % n == 0 {print ""}' | sed '/^HAPPY/s/^/Flow Type\: /' | sed '/^SAD/s/^/Flow Type\: /' | sed '$d'
Flow Type: HAPPY
3_step_minimal_foundation_no_prefill_HAPPY
3_step_minimal_foundation_no_prefill_HAPPY
Flow Type: HAPPY
fullform_no_prefill_HAPPY
fullform_no_prefill_HAPPY
Flow Type: HAPPY
fullform_mobile_foundation_no_prefill_HAPPY
fullform_mobile_foundation_no_prefill_HAPPY
Flow Type: SAD
3_step_minimal_foundation_SAD
3_step_minimal_foundation_SAD
Flow Type: SAD
fullform_SAD
fullform_SAD
Flow Type: SAD
fullform_mobile_foundation_SAD
fullform_mobile_foundation_SAD
Flow Type: HAPPY_PLUS_OPTIONS
3_step_minimal_foundation_HAPPY_PLUS_OPTIONS
3_step_minimal_foundation_HAPPY_PLUS_OPTIONS
Flow Type: HAPPY_PLUS_OPTIONS
fullform_HAPPY_PLUS_OPTIONS
fullform_HAPPY_PLUS_OPTIONS
我想要的輸出:
Flow Type: HAPPY
Flow Name: 3_step_minimal_foundation_no_prefill
File Name: 3_step_minimal_foundation_no_prefill_HAPPY
Flow Type: HAPPY
Flow Name: fullform_no_prefill
File Name: fullform_no_prefill_HAPPY
Flow Type: HAPPY
Flow Name: fullform_mobile_foundation_no_prefill
File Name: fullform_mobile_foundation_no_prefill_HAPPY
Flow Type: SAD
Flow Name: 3_step_minimal_foundation
File Name: 3_step_minimal_foundation_SAD
Flow Type: SAD
Flow Name: fullform
File Name: fullform_SAD
Flow Type: SAD
Flow Name: fullform_mobile_foundation
File Name: fullform_mobile_foundation_SAD
Flow Type: HAPPY_PLUS_OPTIONS
Flow Name: 3_step_minimal_foundation
File Name: 3_step_minimal_foundation_HAPPY_PLUS_OPTIONS
Flow Type: HAPPY_PLUS_OPTIONS
Flow Name: fullform
File Name: fullform_HAPPY_PLUS_OPTIONS
有沒有辦法刪除/保留編號為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
帶有評論的修訂版(致湯姆·費內奇)
awk -vRS= '{ # set awk to paragraph mode
sub("_" $3, "", $4) # remove name from field suffix
$4 = "\nFlow Name: " $4 # construct new fields with header and newline
$5 = "\nFile Name: " $5 "\n" # extra new line for record separation
print # print all fields
}'
沒有太多。 您將記錄定義為完整的文本塊,而不是每一行(這解決了一半問題)。 根據您的格式,我們可以通過索引來引用各個字段。 從定義為另一字段的一個字段中刪除后綴,並准備帶有標題的其他字段。
好的,對於刪除與下一行匹配的行中從下划線到行尾的所有內容的基本功能,此過程非常簡單。 這是兩個選項,其中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
但這改變了兩行中的第二行。 對於所需的其他格式,您似乎想要修改兩行的第一行。 這使得這稍微復雜一點...
為了從所需的文本轉到所需的文本,讓我們以另一種方式看待,並假設兩條重復的行始終出現在以“ Flow Type:”開頭的行之后。
awk '
/^Flow Type:/ {
print;
getline one; getline two
if (one == two) {
sub(/_[^_]+$/,"",one);
print "Flow Name: " one;
print "File Name: " two;
} else {
print one; print two
}
next;
}
1
' inputfile
但是我們也可以處理您的原始HTML。
在sed中,模式識別非常有趣。 這是GNU sed中的一個:
sed -r 's|<tr><td><a href="([^/]+)/(([^"]+)_[^_]+)".*|Flow Type: \1\nFlow Name: \3\nFile Name: \2|' input.html
這是需要GNU sed的換行符( \\n
); 從結構上來說,它只是普通的sed。 此解決方案無法在* BSD或OSX中使用。
編輯 :根據對potong答案的評論,在OSX中可用的一種變體是這樣的:
<input.html sed -n 's/^.*"\\([^"\\/]*\\)\\/\\(\\([^"]*\\)_\\1\\)".*/Flow Type: \\1|Flow Name: \\3|File Name: \\2|/p' | tr '|' '\\n'`
或者,如果您更喜歡ERE而不是BRE:
<input.html sed -E 's|<tr><td><a href="([^/]+)/(([^"]+)_[^_]+)".*|Flow Type: \\1#Flow Name: \\3#File Name: \\2#|' | tr '#' '\\n'
這解決了OSX sed無法將換行符插入到sststute的替換字符串中的限制。 相反,我們插入一個否則未使用的字符,並使用tr
將其轉換為換行符。
為了在awk中實現相同的目標(即處理HTML),您可以使用以下方法:
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);
}'
這可能對您有用(GNU sed):
sed -nr 's/^.*"([^"\/]*)\/(([^"]*)_\1)".*/Flow Type: \1\nFlow Name: \3\nFile Name: \2\n/p' file
使用擴展的正則表達式,並且不會自動打印每一行。 匹配所需的字符串,並使用反向引用提取所需的輸出。 僅在成功替換后打印。
可能適用於其他sed的替代解決方案:
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
這就是我提出的解決方案。 它可以滿足我的需求。 我最終指定了要截斷的實際字符串,現在可以了。 將來,我將改進此解決方案以使其更向前兼容。 感謝大家的幫助!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.