我与一位校对员合作,我为每 N 个字符支付一定的费用(例如 500000)。他(通常)按字母顺序创建/编辑文件。内容/文件名采用(非拉丁)utf-8。简单的纯文本 Markdown (.md) 或 org (.org) 文件。
我需要找到一种有效的方法来为自己记下他的“N 个字符里程碑”,以便我知道何时向他付款。举个例子,假设我上次付钱给他,直到文件“aab.md”中的字符号 3036。他完成了该文件,继续处理“aac.md”、“aad.md”,现在位于“csdw.md”上。
- 我如何“测量”该流中的 N 个字符(包括所有内容:标点符号、空格、数字、换行符、大括号等)(假设所有字符都位于同一目录中)?即,我需要一个 bash 命令,它将获取“aab.md”、3036 和 N 作为输入,并提供类似以下内容的内容:“csaw.md”、5023(意味着 N 个字符在该文件中以该字母结尾)。
- 如何列出上一个命令中所包含的文件?
- 这不太重要,但如果可能的话 - 如果文件分布在多个目录中(也是按字母顺序排列),那么 #1 中的命令会是什么样子,就像他上次停在文件“a/aab.txt”中的字符 3036 上一样。 md”并且现在位于“np/csdw.md”?
我发现它cat * | wc -m
可以在所有文件中提供字符数量,但距离我需要的还很远。
答案1
我建议使用zsh
代替bash
,这将更容易获得自 以来新文件的排序递归列表aab.md
。
#! /bin/zsh -
last_file=aab.md offset_in_last_file=3036 n=500000
new_files=(**/*.(md|org)(N))
new_files=($new_files[(Re)$last_file,-1])
(($#new_files)) && perl -Ci -sne '
$l = length; $go += $l; $o += $l;
if ($go >= $n) {
printf qq(file="%s", line=%d, char-offset=%d\n), $ARGV, $., $o + $n - $go;
exit;
}
$o = 0 if eof' -- -go=-$offset_in_last_file -n=$n ./$^new_files
对于字素簇数而不是字符数,请替换$l = length
为$l = () = /\X/g
。例如é
,写为U+0065U+0301
1 个字素簇,用 2 个字符(UTF-8 中为 3 个字节)表示,而写为 U+00E9 时,为 1 个字素簇和 1 个字符(2 个字节)。
使用 bash 4.4+ 和 GNU awk
,您可以执行类似的操作来构造$new_files
数组
shopt -s nullglob extglob globstar
readarray -td '' new_files < <(
printf '%s\0' **/*.@(md|org) |
L=$last_file awk -v RS='\0' -v ORS='\0' '$0 == ENVIRON["L"], 0'
)
对于bash
,您还需要替换./$^new_files
为"${new_files[@]/#/.\/}"
。 (我们添加前缀以避免以或 、、 、 空格开头./
的文件名出现问题...-
|
<
>