我正在嘗試用 bash 在多個檔案中用“@”替換每 4 次出現的“_”。
例如
foo_foo_foo_foo_foo_foo_foo_foo_foo_foo..
會成為
foo_foo_foo_foo@foo_foo_foo_foo@foo_foo...
#perl -pe 's{_}{ $n % 4 ? $& : "@"}ge' *.txt
我已經嘗試過 perl,但問題是它替換了從最后一個檔案開始的每 4 個 _。因此,例如,某些檔案的第一個 _ 被替換,因為它不是以 0 計數開始每個新檔案,而是從前一個檔案繼續。
我努力了:
#awk '{for(i=1; i<=NF; i ) if($i=="_") if( count%4==0) $i="@"}1' *.txt
但這也行不通。
使用 sed 我找不到一種方法來繼續替換每 4 次出現,因為每個檔案中有不同數量的 _ 。有些檔案有 20 _,有些有 200 _。因此,我無法指定范圍。
我真的迷失了怎么辦,有人可以幫忙嗎?
uj5u.com熱心網友回復:
您只需要重置 perl 中的計數器,eof以告知它何時完成讀取每個檔案:
perl -pe 's{_}{ $n % 4 ? "_" : "@"}ge; $n = 0 if eof' *.txt
uj5u.com熱心網友回復:
這可能是您想要的,使用 GNU awk 進行 RT:
$ awk -v RS='_' '{ORS=(FNR%4 ? RT : "@")} 1' file
foo_foo_foo_foo@foo_foo_foo_foo@foo_foo..
它一次只將每個_- 分隔的字串讀入記憶體 1 ,因此無論您的輸入檔案有多大,_它都應該作業,假設其中有 s 。
它假設您要_在整個檔案中每 4 次替換一次,而不是在單獨的行中替換一次。
uj5u.com熱心網友回復:
一個簡單的sed可以處理這個:
s='foo_foo_foo_foo_foo_foo_foo_foo_foo_foo'
sed -E 's/(([^_] _){3}[^_] )_/\1@/g' <<< "$s"
foo_foo_foo_foo@foo_foo_foo_foo@foo_foo
解釋:
(: 開始捕獲組 #1([^_] _){3}: 匹配匹配 1 個非_字符,后跟一個_. 重復此組 3 次以匹配 3 個這樣的單詞_[^_]: 匹配 1 個非_字符
): 結束捕獲組 #1_: 匹配一個_- 替換是用 a
\1@替換 4th_@
uj5u.com熱心網友回復:
使用 GNU sed:
sed -nsE ':a;${s/(([^_]*_){3}[^_]*)_/\1@/g;p};N;ba' *.txt
-n禁止自動列印,-s單獨處理每個檔案,-E使用擴展正則運算式。
a該腳本是標簽( :a) 和分支到標簽a命令 ( )之間的回圈ba。每次迭代都將下一行輸入附加到模式空間 ( N)。這樣,在讀取最后一行之后,模式空間包含整個檔案(*)。在最后一次迭代中,當最后一行被讀取 ( $) 時,替換命令 ( ) 將模式空間中的s每 4 個替換為( ) 并列印 ( ) 結果。_@s/(([^_]*_){3}[^_]*)_/\1@/gp
當您對結果感到滿意時,您可以更改選項:
sed -i -nE ':a;${s/(([^_]*_){3}[^_]*)_/\1@/g;p};N;ba' *.txt
就地修改檔案,或者:
sed -i.bkp -nE ':a;${s/(([^_]*_){3}[^_]*)_/\1@/g;p};N;ba' *.txt
就地修改檔案,但保留*.txt.bkp每個檔案的備份。
(*) 請注意,如果您有非常大的檔案,這可能會導致記憶體溢位。
uj5u.com熱心網友回復:
使用您顯示的示例,請嘗試以下awk程式。已經創建了一個awk名為fieldNumwhere 我分配4給它的變數,因為 OP 需要@在每 4th 之后輸入_,您也可以根據需要保留它。
awk -v fieldNum="4" '
BEGIN{ FS=OFS="_" }
{
val=""
for(i=1;i<=NF;i ){
val=(val?val:"") $i (i%fieldNum==0?"@":(i<NF?OFS:""))
}
print val
}
' Input_file
uj5u.com熱心網友回復:
和GNU awk
$ cat ip.txt
foo_foo_foo_foo_foo_foo_foo_foo_foo_foo
123_45678_90
_
$ awk -v RS='(_[^_] ){3}_' -v ORS= '{sub(/_$/, "@", RT); print $0 RT}' ip.txt
foo_foo_foo_foo@foo_foo_foo_foo@foo_foo
123_45678_90
@
-v RS='(_[^_] ){3}_'設定輸入記錄分隔符以覆寫四個序列_(與此分隔符匹配的文本將通過RT)-v ORS=空輸出記錄分隔符sub(/_$/, "@", RT)最后更改_為@- 用于
-i inplace就地編輯。
uj5u.com熱心網友回復:
如果計數應為每一行重置:
perl -pe's/(?:_[^_]*){3}\K_/\@/g'
$ cat a.txt
foo_foo_foo_foo_foo_foo_foo_foo_foo_foo
foo_foo_foo_foo_foo_foo_foo_foo_foo_foo
$ perl -pe's/(?:_[^_]*){3}\K_/\@/g' a.txt a.txt
foo_foo_foo_foo@foo_foo_foo_foo@foo_foo
foo_foo_foo_foo@foo_foo_foo_foo@foo_foo
foo_foo_foo_foo@foo_foo_foo_foo@foo_foo
foo_foo_foo_foo@foo_foo_foo_foo@foo_foo
如果不應該為每一行重置計數,而是應該為每個檔案重置:
perl -0777pe's/(?:_[^_]*){3}\K_/\@/g'
導致整個-0777檔案被視為一行。這會導致計數跨行正常作業。
但是由于每個檔案都使用了一個新的匹配項,所以檔案之間的計數會被重置。
$ cat a.txt
foo_foo_foo_foo_foo_foo_foo_foo_foo_foo
foo_foo_foo_foo_foo_foo_foo_foo_foo_foo
$ perl -0777pe's/(?:_[^_]*){3}\K_/\@/g' a.txt a.txt
foo_foo_foo_foo@foo_foo_foo_foo@foo_foo
foo_foo_foo@foo_foo_foo_foo@foo_foo_foo
foo_foo_foo_foo@foo_foo_foo_foo@foo_foo
foo_foo_foo@foo_foo_foo_foo@foo_foo_foo
為避免一次讀取整個檔案,您可以繼續使用相同的方法,但添加以下內容:
$n = 0 if eof;
請注意,eof這與eof()! 見eof。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/422144.html
標籤:
