是否有一種方法可以逐個字符地遍歷文件字符並根據特定條件有選擇地替換字符?如何有效地逐個處理文件的字符
我發現使用while
循環和sed
實用的方式:
while IFS= read -r -N 1 old; do
...
sed -i 's/'$old'/'$new'/g' "$1"
done < "$1"
我認爲這樣的做法是對大文件非常慢。
有沒有一種方法可以更高效地實現這一點?
是否有一種方法可以逐個字符地遍歷文件字符並根據特定條件有選擇地替換字符?如何有效地逐個處理文件的字符
我發現使用while
循環和sed
實用的方式:
while IFS= read -r -N 1 old; do
...
sed -i 's/'$old'/'$new'/g' "$1"
done < "$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"
通過刪除管道並在'output ='''之前加入'[[-z「$ line」]] && continue'應該變得更快。如果行爲空,則運算符'-z'返回true,'continue'轉到文件的下一行。 –
一次加載整個文件,生成所需的輸出然後一次寫出全部文件會快很多。
你可以這樣做:
input=$(<"$1")
output=''
for ((i=0; i<${#input}; i++)); do
old=${input:i:1}
...
output+=$new
done
printf '%s' "$output" > "$1"
有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"
-i inplace
拿到行爲相同與sed -i
。
請添加例如輸入和輸出的要求,也許你想要的提供有關「一定條件」的更多細節。 替代字符的規範工具是'sed'或'tr'。 –
該示例不像列出的那樣工作。在您讀取文件的同時,您似乎正在用'sed'進行編輯。 –
是的,每個單個字符都調用'sed'會很慢。考慮編寫一個'awk'腳本來處理一個進程中的所有I/O。 – chepner