bash - 使用gawk慢速多次编辑同一个文件
问题描述
我运行一个测试环境,在那里我用 lorem alg 创建了 40 000 个测试文件。文件大小在 200k 到 5 MB 之间。我想修改很多随机文件。我将通过删除 2 行并使用 base64 字符串插入 1 行来更改 5% 的行。
问题是这个过程每个文件需要很多时间。我尝试通过将 testfile 复制到 ram 并在那里进行更改来修复,但我看到一个线程只使用一个完整的核心,而 gawk 显示最多的 cpu 工作。我正在寻找一些解决方案,但我找不到正确的建议。我认为 gawk 可以一步完成,但是对于大文件,当我使用“getconf ARG_MAX”进行计算时,我会得到一个很长的字符串。
我怎样才能加快速度?
zeilen=$(wc -l < testfile$filecount.txt);
durchlauf=$(($zeilen/20))
zeilen=$((zeilen-2))
for (( c=1; c<=durchlauf; c++ ))
do
zeile=$(shuf -i 1-$zeilen -n 1);
zeile2=$((zeile+1))
zeile3=$((zeile2+1))
string=$(base64 /dev/urandom | tr -dc '[[:print:]]' | head -c 230)
if [[ $c -eq 1 ]]
then
gawk -v n1="$zeile" -v n2="$zeile2" -v n3="$zeile3" -v s="$string" 'NR==n1{next;print} \
NR==n2{next; print} NR==n3{print s}1' testfile$filecount.txt > /mnt/RAM/tempfile.tmp
else
gawk -i inplace -v n1="$zeile" -v n2="$zeile2" -v n3="$zeile3" -v s="$string" 'NR==n1{next; print} \
NR==n2{next; print} NR==n3{print s}1' /mnt/RAM/tempfile.tmp
fi
done
解决方案
假设:
- 生成
$durchlauf
(一个数字)随机行号;我们将单个数字称为n
... - 从输入文件中删除编号的行
n
并替换它们的位置...n+1
- 插入
$string
(随机生成的base64
字符串) - 这个随机行号列表不能有任何连续的行号
正如其他人指出的那样,您希望将自己限制为gawk
每个输入文件一次调用。
新的方法:
- 生成
$durchlauf
(计数)随机数(见gen_numbers()
函数) - 生成
$durchlauf
(计数)base64
字符串(我们将重用 Ed Morton 的代码) paste
将这 2 组数据放入单个输入流/文件中- 将 2 个文件提供给
gawk
...paste
结果和要修改的实际文件 - 我们将无法使用
gawk
's-i inplace
,因此我们将使用中间 tmp 文件 - 当我们在输入文件中找到匹配行时,我们将1)插入
base64
字符串,然后2)跳过/删除当前/下一个输入行;这应该解决我们有两个不同的随机数的问题+1
确保我们不会生成连续行号的一个想法:
- 将我们的行号集合分解为范围,例如,将 100 行分成 5 个范围 =>
1-20
/21-40
/41-60
/61-80
/81-100
- 将每个范围的末尾减 1 ,例如,
1-19
////21-39
41-59
61-79
81-99
- 用于在每个范围之间生成数字(这往往比可比较的调用
$RANDOM
至少快一个数量级)shuf
我们将使用一个函数来生成我们的非连续行号列表:
gen_numbers () {
max=$1 # $zeilen eg, 100
count=$2 # $durchlauf eg, 5
interval=$(( max / count )) # eg, 100 / 5 = 20
for (( start=1; start<max; start=start+interval ))
do
end=$(( start + interval - 2 ))
out=$(( ( RANDOM % interval ) + start ))
[[ $out -gt $end ]] && out=${end}
echo ${out}
done
}
样品运行:
$ zeilen=100
$ durchlauf=5
$ gen_numbers ${zeilen} ${durchlauf}
17
31
54
64
86
paste/gen_numbers/base64/tr/gawk
想法的展示:
$ zeilen=300
$ durchlauf=3
$ paste <( gen_numbers ${zeilen} ${durchlauf} ) <( base64 /dev/urandom | tr -dc '[[:print:]]' | gawk -v max="${durchlauf}" -v RS='.{230}' '{print RT} FNR==max{exit}' )
这会产生:
74 7VFhnDN4J...snip...rwnofLv
142 ZYv07oKMB...snip...xhVynvw
261 gifbwFCXY...snip...hWYio3e
主要代码:
tmpfile=$(mktemp)
while/for loop ... # whatever OP is using to loop over list of input files
do
zeilen=$(wc -l < "testfile${filecount}".txt)
durchlauf=$(( $zeilen/20 ))
awk '
# process 1st file (ie, paste/gen_numbers/base64/tr/gawk)
FNR==NR { ins[$1]=$2 # store base64 in ins[] array
del[$1]=del[($1)+1] # make note of zeilen and zeilen+1 line numbers for deletion
next
}
# process 2nd file
FNR in ins { print ins[FNR] } # insert base64 string?
! (FNR in del) # if current line number not in del[] array then print the line
' <( paste <( gen_numbers ${zeilen} ${durchlauf} ) <( base64 /dev/urandom | tr -dc '[[:print:]]' | gawk -v max="${durchlauf}" -v RS='.{230}' '{print RT} FNR==max{exit}' )) "testfile${filecount}".txt > "${tmpfile}"
# the last line with line continuations for readability:
#' <( paste \
# <( gen_numbers ${zeilen} ${durchlauf} ) \
# <( base64 /dev/urandom | tr -dc '[[:print:]]' | gawk -v max="${durchlauf}" -v RS='.{230}' '{print RT} FNR==max{exit}' ) \
# ) \
#"testfile${filecount}".txt > "${tmpfile}"
mv "${tmpfile}" "testfile${filecount}".txt
done
运行代码的简单示例awk
:
$ cat orig.txt
line1
line2
line3
line4
line5
line6
line7
line8
line9
$ cat paste.out # simulated output from paste/gen_numbers/base64/tr/gawk
1 newline1
5 newline5
$ awk '...' paste.out orig.txt
newline1
line3
line4
newline5
line7
line8
line9
推荐阅读
- bootstrap-4 - Boostrap 4 多选
- git - git操作顺序
- javascript - 如何使用 React.createRef() 在 React 中访问多个 Dom 元素
- iot - CoAP pub/sub 传输可靠性
- javascript - 将 Vue.js Firebase-Object 包装到 onAuthStateChanged 处理程序中?
- javascript - 我的功能存在问题,我似乎无法修复。目前,它说Cannot read property 'split' of undefined at joinslots
- python - 'aiohttp.ClientSession' 缓存不起作用
- email - 如何使用 ThingsBoard 规则链中的“发送电子邮件”规则节点发送 Gmail 电子邮件?
- html - 以角度将数据从父组件传递到子组件
- css - 如何使用 max 函数调整 CSS 网格行高?