我刚刚发现,我最喜欢的全文索引程序 Recoll 不会对电子表格单元格中的公式内容进行索引。它会对只包含数字或文本的单元格进行索引,也会对计算结果进行索引,但不会对进行计算的公式进行索引。
有谁知道如何在充满电子表格的目录中搜索公式中出现的字符串,而无需在电子表格应用程序中打开每个文件并在那里搜索?
我熟悉 grep,但它对电子表格格式并不熟悉,并且大多数提取电子表格内容的工具的行为都像 Recoll,它们忽略公式并仅提取结果。
以下是我的意思的说明。如果我搜索 G6 的值 (1575.50),Recoll 和其他工具通常可以找到此电子表格,但我希望能够找到使用特定类型的公式计算值的示例 - 在这种情况下,我将搜索 IFERROR(。
答案1
如果您的电子表格是使用 LibreOffice Calc(或类似软件)制作的,那么它们实际上是zip
文件。以下脚本将起作用:
#!/bin/bash
for f in $(find . -name "*.ods" -type f)
do
unzip -qq "$f" content.xml
if grep -q [search string] ./content.xml; then
echo "$f contains the search string"
fi
rm -rf ./content.xml
done
其作用如下:
- 在文件夹中查找电子表格
- 对于每个电子表格文件,其中的
unzip
文件content.xml
- 做
grep [search string] content.xml
- 如果匹配,则向用户写一条消息
- 删除文件
content.xml
用要搜索的字符串替换[search string]
,或使其成为运行时提供的变量。
确保文件夹中还没有文件content.xml
,否则文件将会丢失。
这些-q
标志仅仅是为了抑制输出。
如果需要不区分大小写的搜索,请添加-i
到grep
命令中。
这将在单元格中的公式中找到搜索字符串,但(显然)不会找到以下字符串:结果公式。例如,如果您的公式是,=concat('nice ';'day')
它将不会找到nice day
。但它会找到nice
和day
。
答案2
谢谢 Jos,这是一个非常有用的答案,解决了问题。我添加了一些对我的用例有帮助的细微更改:
for f in $(find . -iname "*.ods" -type f)
do
unzip -qq "$f" content.xml 2>/dev/null
if grep -q "$1" ./content.xml 2>/dev/null; then
echo "$f contains the search string $1"
fi
rm -rf ./content.xml
done
-iname 使文件名查找不区分大小写
2>/dev/null 丢弃错误消息,这些消息在这里没有用
$1 是第一个命令行参数,因此我可以将其用作每次具有不同搜索字符串的脚本。
现在您展示了原理,我知道 Excel .xlsx 文件实际上也是 zip 文件,但我认为内部结构稍微复杂一些。我也将研究如何使用它们。
答案3
我对 .xlsx 的解决方案比 .ods 稍微复杂一些,但不是很多……
for f in **/*.xlsx; do # Whitespace-safe and recursive
unzip -qq -o -j -d /tmp "$f" xl/worksheets/*.xml 2>/dev/null
# -o overwrite;
# -j do not recreate directory structure
# -d /path tells it where to extract to
if grep -i -q $1 /tmp/*.xml ; then
echo -e "$f contains the search string $1"
fi
rm -rf /tmp/*.xml
done
与 .ods 版本不同,您无法预测解压后生成的 xml 文件的文件名,因此我将它们解压到系统 /tmp 目录,然后在处理每个 .xlsx 后从此处删除所有 xml。这就是 /tmp 的用途...
本例顶部的“for”行实际上要好得多比上面 ods 示例中的 line 等效,因为它可以正确处理带有空格的路径和文件名。