如何修改以下 bash 代码以使其按某个数值选择文件?例如,selcnt=3
每三个文件搜索一次模式,selcnt=5
每五个文件搜索一次模式,等等。
grep -r -l "${isufx[@]}" -e "$ptrn" -- "${fdir[@]}" |
while read f; do
echo -e $(tput setaf 46)"==> $f <==\n"$(tput sgr0)
grep -ni "${ictx[@]}" -e "$ptrn" -- "$f"
echo ""
done
目的是加快搜索过程,但保持输出一次分成一个文件。加快进程的一种方法是针对不同的运行处理不同的文件,例如,通过跳过文件。
Run 1: Start from file 1 and skipping two files;
Run 2: Start from file 2 and skipping two files;
Run 3: Start from file 2 and skipping two files.
作为第一次尝试,我使用了
ist=1; isk=2
grep --null -r -l "${isufx[@]}" -e "$ptrn" -- "${fdir[@]}" |
sed -z '${ist}~${isk}!d' |
while IFS= read -rd '' fl; do
printf '%s\n\n' "${grn}==> $fl <==${sgr}"
grep -ni "${ictx[@]}" -e "$ptrn" -- "$fl"
done
但我收到错误
sed: -e expression #1, char 0: unmatched `{'
答案1
要从 的输出中选择每三个文件grep -l
,首先请注意,您需要切换到 NUL 分隔列表以便能够处理任意文件路径(添加--null
/-Z
选项grep
),然后您可以选择:
gawk -v RS='\0' -v ORS='\0' 'NR ~ 3 == 1'
sed -z '1~3!d' # assuming GNU sed
perl -0ne 'print if $. % 3 == 0'
然后,要循环该输出,它将是(使用 zsh 或 bash):
green=$(tput setaf 46) sgr0=$(tput sgr0)
while IFS= read -rd '' file; do
printf '%s\n\n' "$green==> $file <==$sgr0"
...
done
您不想使用,echo -e
因为这会破坏文件名中出现的反斜杠字符。
所以,把它们放在一起:
green=$(tput setaf 46) sgr0=$(tput sgr0)
grep --null -r -l "${isufx[@]}" -e "$ptrn" -- "${fdir[@]}" |
sed -z '1~3!d' |
while IFS= read -rd '' file; do
printf '%s\n\n' "$green==> $file <==$sgr0"
grep -ni "${ictx[@]}" -e "$ptrn" -- "$file"
done
但如果重点是并行运行其中 3 个循环,每个循环处理 3 个批次中的 1 个,那么这就是 GNU 之类的东西的用途parallel
:
grep --null -r -l "${isufx[@]}" -e "$ptrn" -- "${fdir[@]}" |
PARALLEL_SHELL=bash \
GREEN=$(tput setaf 46) \
SGR0=$(tput sgr0) \
PTRN=$ptrn \
parallel -m0kj3 '
for file in {}; do
printf "%s\n\n" "$GREEN==> $file <==$SGR0"
grep -ni '"${ictx[@]@Q}"' -e "$PTRN" -- "$file"
done'
在这里,通过环境变量传递标量变量,否则使用${param@Q}
bash-4.4+ 将数组定义传递到内部 bash 实例(这里假设值不包含任何特殊的字符串 like parallel
,{}
... {.}
) 。
或者更好的是,避免上述限制:
grep --null -r -l "${isufx[@]}" -e "$ptrn" -- "${fdir[@]}" |
PARALLEL_SHELL=bash TRANSFER_CODE=$(
green=$(tput setaf 46) sgr0=$(tput sgr0)
typeset -p green sgr0 ptrn ictx
) parallel -m0kj3 '
eval "$TRANSFER_CODE"
for file in {}; do
printf "%s\n\n" "$green==> $file <==$sgr0"
grep -ni "${ictx[@]" -e "$ptrn" -- "$file"
done'
这次使用 的输出typeset -p
将所有这些变量(数组或非数组)的定义传输到内部bash
。
parallel
将并行启动 3 个bash
shell,每个 shell 处理三分之一的文件,并在最后按顺序重新组合各自的输出。
无论如何,如果瓶颈是 I/O(从磁盘读取数据的速度),那么并行运行这些东西将无济于事。