2017-02-11 40 views
1

是否有一種方法可以逐個字符地遍歷文件字符並根據特定條件有選擇地替換字符?如何有效地逐個處理文件的字符

我發現使用while循環和sed實用的方式:

while IFS= read -r -N 1 old; do 
    ... 
    sed -i 's/'$old'/'$new'/g' "$1" 
done < "$1" 

我認爲這樣的做法是對大文件非常慢。

有沒有一種方法可以更高效地實現這一點?

+5

請添加例如輸入和輸出的要求,也許你想要的提供有關「一定條件」的更多細節。 替代字符的規範工具是'sed'或'tr'。 –

+3

該示例不像列出的那樣工作。在您讀取文件的同時,您似乎正在用'sed'進行編輯。 –

+1

是的,每個單個字符都調用'sed'會很慢。考慮編寫一個'awk'腳本來處理一個進程中的所有I/O。 – chepner

回答

-1

我終於找到了我一直在尋找!我用一個while循環讀取行編寫了下面的代碼,一個用於循環讀取特定行中的每個字符。這種方式更快,並且新線路也保持不變!我會很高興,如果這個答案也幫助其他人!

#!/bin/bash 
lineCounter=1 
while IFS='' read -r line || [[ -n "$line" ]]; do 
    output='' 
    for ((i=0; i<${#line}; i++)); do 

     oldChar=$(printf "${line:$i:1}") 

     ...Compute newChar... 

     output+=$newChar 

    done 
    line2="" 
    line2+=$lineCounter 
    line2+="s" 
    sed -i "$line2/.*/$output/" "$1" 
    lineCounter=$((($lineCounter) +1)) 
done < "$1" 
+0

通過刪除管道並在'output ='''之前加入'[[-z「$ line」]] && continue'應該變得更快。如果行爲空,則運算符'-z'返回true,'continue'轉到文件的下一行。 –

0

一次加載整個文件,生成所需的輸出然後一次寫出全部文件會快很多。

你可以這樣做:

input=$(<"$1") 
output='' 
for ((i=0; i<${#input}; i++)); do 
    old=${input:i:1} 
    ... 
    output+=$new 
done 

printf '%s' "$output" > "$1" 
+0

這適用於一行文件。但是,我認爲如果文件有兩行或多行,在新文件中將只有一行,是正確的? – Cache

+0

那麼'input = $(

+0

雖然與OP的方法相比,這肯定會加快速度,但它總體上仍然很慢,因爲_Bash_代碼中的循環是_inherently_ slow。另外,如您所述,您的方法 要求將整個文件讀取到內存中_作爲整體,這對於大型輸入文件可能會有問題。 – mklement0

0

2性能殺手在你的方法:

  • 使用外殼環來處理數據。

  • 調用在該循環的每次迭代外部效用(sed

    • 具體來說,我們沒有理由來重寫你的循環的每次迭代文件。
    • 另外,正如已經指出的那樣,您在每次迭代中將替換爲中的文件,這是行不通的。

替代

  • 如已提出,sed可能是你需要它,因爲它支持鏈接多個s///電話(帶;)以及使用字符在給定的呼叫中設置範圍

  • tr是一種有效的工具,還支持集合和範圍,但它被限制爲1對1的字符映射(不能映射給定字符以多個輸出字符)。

如果你真的需要過程字符字符使用文本處理工具而不是shell代碼;例如,與awk

$ awk -F'\0' '{ for(i=1;i<=NF;++i) { printf "[%s]", $i }; print "" }' <<<$'abc\ncde' 
[a][b][c] 
[c][d][e] 
  • -F '\0'告訴awk打破各行成單個字符,$1表示第一字符,...,和NF反映到行中的字符計數。

  • 示例命令簡單地包圍每個字符。在[...]中演示了每個字符處理的工作原理; print ""最後只是發出尾隨\n

  • 要使用就地升級(非嚴格意義上),結合使用此:
    awk -F'\0' '{ ... }' "$1" > "$1.$$" && mv "$1.$$" "$1"

    • 隨着GNU awk中V4.1 +,你也可以使用-i inplace拿到行爲相同與sed -i