我和我的同事写了大量的Jupyter notebooks。在其中有效搜索是一个普遍的问题。
jupyter笔记本是JSON文件,因此使用诸如grep之类的传统搜索方法很乏味。没有一点修补是ð
最初,我在Internet上找到了一个名为“ NBGREP”的脚本,但对我们来说并没有解决。所以,我写了自己的版本。
它需要jq进行JSON处理,而GNU则需要笔记本中的concurrent搜索。
无论如何,这些都是很棒的工具,对于数据科学家来说可能非常方便。 jq
使得可以轻松地针对JSON文件编写查询,而parallel
则可以用来以非常简单的方式同时执行任何类型的代码。
它们易于安装:
Debian和朋友:
sudo apt-get install jq parallel
macos
brew install jq parallel
您可以找到我的脚本作为要点here,或者如果由于某种原因无法平行安装,则是non-parallel version。我专门为这篇文章写了一个非并行版本,所以请通知我是否有问题。
因此,当您运行它时:
nbgrep 'read_[a-z]'
您会得到类似的东西:
./foo/bar.ipynb
df_a = pd.read_csv(
df_b = pd.read_csv(
./foobar/barfoo.ipynb
G = obonet.read_obo(url)
(我必须重命名的大部分结果)
脚本:
#!/bin/bash
set -euo pipefail
catch() {
echo "ERROR $1 occurred on $2"
}
trap 'catch $? $LINENO' ERR
pattern="${1? You must provide a search pattern}"
jupyter-search() {
file="$1"
pattern="$2"
matches=$(< "$file" jq '.cells[].source[]' -r \
| grep -P "$pattern" \
| xargs -I '%' echo -e "\t%"
)
if [ ! -z "$matches" ]
then
echo "$file"
echo "$matches"
fi
}
export -f jupyter-search
find . \
-type 'f' \
-iname '*.ipynb' \
-not -path '*/.ipynb_checkpoints/*'\
| parallel jupyter-search {} "$pattern"
现在让我们看看脚本的工作原理。
#!/bin/bash
set -euo pipefail
#!/bin/bash
只是告诉内核在哪里可以找到脚本的解释器。 set -euo pipefail
是Bash的“严格模式”。没有它,bash将不会停止在错误-e
上执行脚本执行或遇到未定义的变量-u
。 -o pipefail
将确保如果在管道中发生任何错误(非零退出代码),则整个管道将被视为错误。
catch() {
echo "ERROR $1 occurred on $2"
}
trap 'catch $? $LINENO' ERR
通过以这种方式捕获错误,我们可以看到发生错误的行。
pattern="${1? You must provide a search pattern}"
这是您想在笔记本中找到的搜索模式。它可以是任何类似perl的正则表达方式。如果未提供搜索模式,该行还将提供有用的错误消息。
jupyter-search() {
file="$1"
pattern="$2"
matches=$(< "$file" jq '.cells[].source[]' -r \
| grep -P "$pattern" \
| xargs -I '%' echo -e "\t%"
)
if [ ! -z "$matches" ]
then
echo "$file"
echo "$matches"
fi
}
这是一个bash函数定义。该函数有两个参数:$file
,从第一个位置参数中读取,而搜索$pattern
从第二个读取。让我们专注于搜索部分:
matches=$(< "$file" jq '.cells[].source[]' -r \
| grep -P "$pattern" \
| xargs -I '%' echo -e "\t%"
)
在此,管道的输出(由管道连接的命令|
连接)将分配给matches
变量。
管道的第一个命令将笔记本读取到jq
JSON处理器中,该处理器提取所有代码单元。这些被管道输送到GREP命令中,该命令将给定的$pattern
应用于类似Perl的Regexp -P
。管道中的最后一个命令将列出grep
的匹配项。
函数末尾的if语句将打印结果,鉴于$matches
不是一个空字符串。
export -f jupyter-search
parallel
将在子壳中执行给定代码,该代码不会从父壳(壳执行脚本本身)继承变量。因此,有必要导出先前定义的函数,以便在并行创建的子壳中访问。
find . \
-type 'f' \
-iname '*.ipynb' \
-not -path '*/.ipynb_checkpoints/*'\
| parallel jupyter-search {} "$pattern"
此代码将以.ipynb
扩展名以不敏感的方式找到所有常规文件(不包括符号链接,目录和设备文件)。它将在您启动脚本的目录中递归搜索,仅省略.ipynb_checkpoints
目录。找到的笔记本文件被流传输到parallel
命令中,该命令将jupyter-search
函数应用于它们,并在给定的搜索$pattern
中以与您的CPU核心编号一样多。所有这些过程都会将其结果发送到您的标准输出中,但是并行处理它们不会混乱。
因此,总而言之,我们有一种非常快速的方法来从命令行中搜索jupyter笔记本电脑。我希望你们中的一些人会发现它有帮助。如果您对如何改进它有想法,我愿意接受建议。