有没有办法逐个字符地迭代文件并根据特定条件有选择地替换字符?
我找到了一种使用while
循环和sed
实用程序的方法:
while IFS= read -r -N 1 old; do
...
sed -i 's/'$old'/'$new'/g' "$1"
done < "$1"
我认为这种方法对于大文件来说非常慢。
有没有办法可以更有效地实现这一目标?
答案 0 :(得分:0)
一次加载整个文件会快得多,生成所需的输出然后立即全部写出来。
您可以执行以下操作:
input=$(<"$1")
output=''
for ((i=0; i<${#input}; i++)); do
old=${input:i:1}
...
output+=$new
done
printf '%s' "$output" > "$1"
答案 1 :(得分:0)
您的方法中有 2个性能杀手:
使用 shell循环处理数据。
在该循环的每次迭代中调用外部实用程序(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
反映该行上的字符数
示例命令只包含每个char。在[...]
中证明每个字符的处理工作;最后print ""
只会发出一个尾随\n
。
要将其与就地更新(松散地说)相结合,请使用:
awk -F'\0' '{ ... }' "$1" > "$1.$$" && mv "$1.$$" "$1"
-i inplace
获得与sed -i
相同的行为。答案 2 :(得分:-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"