#!/bin/sh
# platform ... devuan dash
# GPL_3+
cat << 'EEE' > /dev/null
/* fns .... find string, grep & find parser bourne-shell script
* Copyright (C) 2017-2019 Momi-g
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
EEE
# 2-clause BSD license
# https://sites.google.com/site/jdisnard/realpath
cat << 'EEE' > /dev/null
/* Copyright 2010 Jon Disnard. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY Jon Disnard ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of Jon Disnard.
*/
EEE
# readlink -f portable & posix. func_rlp "$file" ..or.. cat file + \000 | func_rlp
func_rlp() {
# GPL_3+ license
# '(' ... for local scope
(
# normalize locale
bk_lcl=`set`
export LC_ALL=C
export LANG=C
pf1='( eval "$bk_lcl" ; cat - )'
rlp_input='cat -'
if [ "$#" != '0' ] ; then
rlp_input='for ii
do
printf "%s\000" "$ii"
done'
fi
# ...awk for detect input err.
eval "$rlp_input" | od -An -to1 -w16 -v | awk -v bf="$0" '
BEGIN{err=1}
$0 ~ /000/ {err=0}
{print $0}
END{
if(NR > 0 && err == 1 ) {
printf("%s: link search err. \134000 not found. sleep.\n", bf) > "/dev/stderr"
for(;;){
system("sleep 1000")
}
}
}' | sed -e 's/ 000/@/g' | tr -d '\n' |
tr ' ' '\134' | tr '@' '\n' | while read -r rlp_A
do
# fname ... dir
rlp_fin=`printf "$rlp_A"'@'`
rlp_fin="${rlp_fin%?}"
# normalize name to have dir data (aaa.txt -> ./aaa.txt etc)
rlp_fin="${rlp_fin%/}"
if [ "${rlp_fin#*/}" = "$rlp_fin" ] ; then
rlp_fin="./$rlp_fin"
fi
rlp_ftail='' #file name only
# kick err files
if ! [ -e "$rlp_fin" ] ; then
# echo "$0: link search err. file not found. '$rlp_fname'" > /dev/stderr
printf '//%s\000' "$rlp_fin"
continue
fi
# split dir + name. -f ... cant get ln, pipe etc.
if ! [ -d "$rlp_fin" ] ; then # -d ! not dir == files
# split dir + filename. and resolve soft link
# ls --show-control-chars
# 表示不可能な文字をそのまま表示 (プログラムが 'ls' で なかった
# り、出力が端末以外の場合は、これがデフォルト動作になる)
# ...つまり、端末に表示せず変数等に代入する時は正確なファイル名が取得できるはず。
# -Lオプションはサイズや日付データのみでファイル名は対象外
rlp_fname="$rlp_fin"
while : # recheck for multiple link (a -> b -> c etc)
do
if ! [ -h "$rlp_fname" ] ; then # -h ... exist & link
break
fi
# 2-clause BSD license
# https://sites.google.com/site/jdisnard/realpath
# use 'ls -l' to get link-dst infomation.
# '->' use as string spliter ... http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html
# need LANG=c ? safety?
# rlp_LANGbk="$LANG"
# LANG="c"
rlp_base=`/bin/ls -l "$rlp_fname" ; printf @` # $() removes end '\n' (posix)
rlp_base="${rlp_base%??}" # aaa\n@ -> aaa ... ls add \n (like echo)
rlp_count=`printf '%s\n' "$rlp_fname" | tr -c '>-' ' ' |
sed -e 's/->/@/g' | tr -d -c '@' | wc -c` # check '->' string(filename, username etc)
rlp_count=$((rlp_count+1))
for ii in `seq 1 $rlp_count ` # ls -h... exist ->
do
rlp_base="${rlp_base#*->}"
done
# debug... ls -al
# /dev/stdin -> /proc/self/fd/0
# /proc/self/fd/0 -> pipe:[3082488] <<< not file. inode system. needs kick
test -e '/'"${rlp_base#*/}" || break
rlp_fname='/'"${rlp_base#*/}" # remove head ' ' ls disp filename (linkfile)
done #while end
# if files, rlp_ftail != '',
rlp_ftail="${rlp_fname##*/}" # filename only
rlp_fdir="${rlp_fname%/*}" # dirname only
else
# fin is dir
rlp_fdir="$rlp_fin"
fi
# normalized. check path reallink
# pwd -P: get full realpath. posix. (2001-?)
# echo @ ... command substitution deletes lineend '\n, \n\n ...'.
# http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_03
# pwd permission... dir exec may make some problem. run at subshell.
(
for ii in skip # jump emulate
do
cd "$rlp_fdir"
if [ "$?" = "1" ] ; then
echo "$0: link search err. dir access failed. ($rlp_fdir)" | eval "$pf1" > /dev/stderr
printf '//%s\000' "$rlp_fdir"
break
fi
rlp_fpath=`pwd -P; printf '@'`
if [ "$rlp_fpath" = '@' ] && [ "$err" != "" ] ; then
echo "$0: link search err. pwd -P failed. ($rlp_fdir)" | eval "$pf1" > /dev/stderr
printf '//%s\000' "$rlp_fdir"
break
fi
rlp_fpath="${rlp_fpath%??}" # aaa\n@ -> aaa ... pwd add \n (like echo)
rlp_fpath="${rlp_fpath%/}" # if aaa/ -> aaa etc
rlp_fname="$rlp_fpath"'/'"$rlp_ftail" # dir has end '/' ... 'aaa/' etc
printf '%s\000' "$rlp_fname"
done
)
done | od -An -to1 -w16 -v | tr -d '\n' |
sed -e 's# 000#@#g' | tr ' ' '\134' | tr '@' '\n' | awk -v name="$0" '
$0 ~ /^.057.057/ {
gsub(/^.057.057/, "", $0)
cmd="printf \047" $0 "\012\047 >/dev/stderr"
printf "%s: link check err. file not found: ", name > "/dev/stderr"
system(cmd)
printf "//"
}
{print $0}' | eval "$pf1"
)
}
# grepだと8ms, sed流しで20ms.ファイルはいっぱいでるからなるべく多めに絞りたい。
# ってことは最速のgrepがいいか。大量にhitするのは検索ワードが悪い=すぐにやり直すだろうから
# ファイルを高速に選別するほうが重要。gnuは-Cの存在が強いからそっち。
# gnuはwhileしても6ms, posixは350ms.
cmd_fulloct="func_rlp"
readlink -zf "$0" --version >/dev/null 2>&1
if [ "$?" = "0" ] ; then
cmd_fulloct=`cat << 'EEE'
xargs -0 -I aaa readlink -zf -- aaa |
od -An -to1 -w16 -v |
sed -e 's/ 000/@/g' | tr -d '\n' | tr ' ' '\134' |
tr '@' '\n'
EEE
`
fi
#---main
# fpath=$(printf `func_rlp "$0"`'@')
# fpath=${fpath%?}
# fname=`basename "$fpath"`
# fdir=${fpath%/*}'/'
# cd "$fdir"
#optcheck--------
# change -+ -> -p plus-minus
for ii
do
if [ "$ii" = "--" ] ; then skip=1 ; fi
if [ "$skip" != "1" ] && [ "${ii%%+*}" = "-" ]; then
ii='-p'"${ii#-+}"
fi
shift
set -- "$@" "$ii"
done
# ini=`cat << 'END'
# -h 0 bool
# -p -1 int '[ $opt_p -ge 0 ]'
# -r 0 int '[ $opt_r -ge -1 ]'
# -o 0 bool
# -B 0 bool
# -f "./" str
# -F 0 bool
# -P 0 bool
# END
# `
# buf=`ckopt "$ini"`
# eval "$buf"
## ---this code is generated by ckopt
# ---optsetting
#-h 0 bool
#-p -1 int '[ $opt_p -ge 0 ]'
#-r 0 int '[ $opt_r -ge -1 ]'
#-o 0 bool
#-B 0 bool
#-f "./" str
#-F 0 bool
#-P 0 bool
ckopt_func () {
if [ "$1" = "-d" ] ; then
eval "opt_${2#?}"'="$3"' # opt_?="$3"
return 0
fi
ckopt_opt="$2"
if [ "$1" = "-e" ] ; then
shift 4
while [ $# -gt 0 ]
do
if [ "$1" != "${1#[#]e}" ] || [ "$1" != "${1#[#]E}" ] ; then
eval "${1#[#]?}"
if [ "$?" != "0" ] ; then
OPTARG="errmsg $ckopt_opt $1"
return 1
fi
fi
shift
done
return 0
fi
if [ "$1" = "-c" ] ; then
shift 3
printf '%s\n' "$1" | tr '[:upper:]' '[:lower:]' | awk '$1 ~ /int/ {exit 1}'
if [ "$?" = "1" ] ; then
shift
set -- "dummy" 'printf "%d" "$OPTARG" >/dev/null 2>&1' "$@"
fi
shift
while [ $# -gt 0 ]
do
eval "$1"
if [ "$?" != "0" ] ; then
OPTARG="errmsg $ckopt_opt $1"
return 1
fi
shift
done
return 0
fi
echo "$0: bug. sleep" >/dev/stderr
while :
do
sleep 1000
done
exit 1
}
# ---dflset
OPTIND=1 # fixed value. posix rule.
OPTERR=0
ckopt_buf=''
ckopt_opt=''
ckopt_func -d -h 0 bool
ckopt_func -d -p -1 int '[ $opt_p -ge 0 ]'
ckopt_func -d -r 0 int '[ $opt_r -ge -1 ]'
ckopt_func -d -o 0 bool
ckopt_func -d -B 0 bool
ckopt_func -d -f "./" str
ckopt_func -d -F 0 bool
ckopt_func -d -P 0 bool
#---getopts loop. break if all args read or detect '--'
while :
do
if [ 0 -eq "$#" ] || [ "${OPTARG%% *}" = "errmsg" ] ; then
break
fi
check_opt='$'"$OPTIND" #add code. debug.
eval "check_opt=\"$check_opt\""
if [ "$check_opt" = "--" ] ; then
shift $OPTIND ; break
fi
getopts ":hp:r:oBf:FP" ckopt_opt "$@" # ":a:bc:f:" etc...
if [ "$?" = "1" ] ; then # detect end/normal args. save general args.
shift $((OPTIND - 1))
if [ "$#" -eq "0" ] ; then
break
fi
ckopt_buf="$ckopt_buf "`printf '%s' "$1" | sed -e "{
s#'#'\"'\"'#g
s/^/'/g
s/$/'/g
}"`
shift
OPTIND=1
continue
fi
# --- your setting
if [ "$ckopt_opt" = "h" ] ; then
opt_h="1"
ckopt_func -c -h 0 bool
continue
fi
if [ "$ckopt_opt" = "p" ] ; then
opt_p="$OPTARG"
ckopt_func -c -p -1 int '[ $opt_p -ge 0 ]'
continue
fi
if [ "$ckopt_opt" = "r" ] ; then
opt_r="$OPTARG"
ckopt_func -c -r 0 int '[ $opt_r -ge -1 ]'
continue
fi
if [ "$ckopt_opt" = "o" ] ; then
opt_o="1"
ckopt_func -c -o 0 bool
continue
fi
if [ "$ckopt_opt" = "B" ] ; then
opt_B="1"
ckopt_func -c -B 0 bool
continue
fi
if [ "$ckopt_opt" = "f" ] ; then
opt_f="$OPTARG"
ckopt_func -c -f "./" str
continue
fi
if [ "$ckopt_opt" = "F" ] ; then
opt_F="1"
ckopt_func -c -F 0 bool
continue
fi
if [ "$ckopt_opt" = "P" ] ; then
opt_P="1"
ckopt_func -c -P 0 bool
continue
fi
# --- your setting end
# hit err. ckopt chars...
# err detect@silent mode
# $?=1 ... detect optend or '--'
# ':' ... detect option, but dont have subargs (OPTARG="factor").
# '?' ... detect unsupported option char (OPTARG="factor") or args end (OPTARG="blank").
# OPTARG ... "" is optend. "a/b/c..." is invalid option
# OPTIND ... if err, OPTIND indicates next (new) arg pos.
OPTARG="errmsg -$OPTARG invalid option / misses subargs"
done
# --- post process. set not optional args & clean & #eE last cmd.
for ii in 1 # dummyjump logic
do
OPTIND=1
# skip
test "${OPTARG%% *}" != "errmsg" || break
ckopt_buf="set -- $ckopt_buf"' "$@"' # set -- 'cmd' .. "$@"
eval "$ckopt_buf"
# run #E cmd. cmd + test $? ... xn
ckopt_func -e -h 0 bool
ckopt_func -e -p -1 int '[ $opt_p -ge 0 ]'
ckopt_func -e -r 0 int '[ $opt_r -ge -1 ]'
ckopt_func -e -o 0 bool
ckopt_func -e -B 0 bool
ckopt_func -e -f "./" str
ckopt_func -e -F 0 bool
ckopt_func -e -P 0 bool
done
if [ "${OPTARG%% *}" = "errmsg" ] ; then
printf "$0: opterr. %s\n" "$OPTARG" >/dev/stderr ; while : ; do sleep 1000 ; done ; exit 1
test 1 = 0
fi
## ---generate by ckopt end
#exit direct option ... 20ms prsopt ...50ms
if [ $? -ne 0 ] ; then
echo "$0: optErr($OPTARG). see -h. sleep 1000" >/dev/stderr
while : ; do sleep 1000 ; done
exit 1
fi
if [ "$opt_h" = "1" ] || [ "$#" = "0" ] ; then
cat << 'EEE'
HowTo (FiNdString from dir files. bourne-shell script)
opt: -h, -+2(range), -r(ecurse -1,0,1,2..), -o(ctal)
-B(asic-regex BRE), -F(ixed, not regex), -f(ilename)
------
ex.) ~$ fns abc str ing (-F -+2 -r 0) >> dfl option
>> /foo/bar/aaa.txt ...find file from './', including words
10- ... ing
11: moo abc ...search range, 'abc' -+2 lines
12- ... 'str'
ex.) ~$ fns 'string' ... one word, almost equals to 'grep string ./*'
~$ fns 'string' -r -1 ...recursive find (-1:non stop 0:pwd 1:pwd+next)
~$ cat a.txt | fns -B '\(b\|B\)ob.*' ... pipein equals (-f 'a.txt')
~$ fns 'abc' -o ...show octal filename. (a.txt -> \141\056\164\170\164)
ex.) ~$ fns -+1 -- abc 'str' '-foo is bar'
...input '--'(opt end) if you want to avoid parsor troubles.
EEE
exit 0
fi
# -f or stdin
sfile="$opt_f"
if [ -p /dev/stdin ] ; then
sfile="/dev/stdin"
fi
# one word
if [ "$#" = "1" ] && [ "$opt_p" = "-1" ] ; then
opt_p=0
fi
if [ "$opt_p" = "-1" ] ; then
opt_p=2
fi
# install ck
buf=0
find -print0 --version >/dev/null 2>&1
buf=$((buf+$?))
grep -Z --version >/dev/null 2>&1
buf=$((buf+$?))
xargs -0 --version >/dev/null 2>&1
buf=$((buf+$?))
mposix=0
if [ "$buf" != 0 ] || [ "$opt_P" = "1" ] ; then
echo "$0: gnu-find,grep,xargs not found or detect -P. run posix mode(slow)" >/dev/stderr
mposix=1
fi
# change regex. if -F un^k\o > [u][n]\^[k][\][o]
# only '^' needs escape.
if [ "$opt_B" = "0" ] ; then
for i in "$@"
do
cmd="printf '%s\n' "'"$i"'" | sed -e '"'s#.#[&]#g;s#\[\^\]#\\^#g'"'"
buf=`eval "$cmd"`
#printf '%s\n' "$buf"
shift
set -- "$@" "$buf"
done
fi
fstword="$1"
charcode="041" # '!', ascii 33@decimal 0041+041 とか\0041 はposixで処理してくれると思う。
while :
do
ws2=`printf '%b' '\'"$charcode"`
ck=`printf '%s\n' "$@" | tr -dc "$ws2" `
if [ "$ck" = "" ] ; then
break
fi
if [ $((charcode + 1)) -gt 254 ] ; then
echo "regex separater err. search word hax too many kinds of char.(o041-o254). sleep" >/dev/stderr
while : ; do sleep 1000 ; done
exit 1
fi
# 進数のままで計算可能だけど出力は10進固定。8に戻す
charcode=`printf '0%o' $((charcode + 1))`
done
ws1='\'"$ws2" #>> \@ \# etc
# echo "@ $charcode $ws1 @"
# 66ms
# exit
# for stream
dmy=""
fstread="" # null comm is ignored(sed)
preread=""
for i in `seq 1 $opt_p`
do
dmy='\060\072\012'"$dmy" #0: *n, head/tail water down.
#output (5/opt_p)lines loop. buffer read
fstread="$fstread"'N;N;' #if opt_p=3 2*3. N;N;N;N;N;N
preread="$preread"'n;H;' # skip headlines
done
#echo "$dmy" | b2rs
#exit 0 #0.084 >> 0.053
# avoid slow comm, 's/(.*)(.*)/\2\1/g' etc
# edit output format
# 入力行を?行ずつ水増しして吐く。スプリッタで等分して正規化
cmd_split="sed -ne '
1 { $fstread }
p
i"'\'"
--:
N;D
'"
quch=`printf '\047\042\047\042\047'` # ' -> '"'"'
# kick if center line doesnt have fstword. pre ... n;H *n
cmd_fst="
:label1
h; $preread
s/^[0123456789]\{1,\}.//1
$ws1$1$ws2 b label3
:label2
/^--:/ ! {n;b label2 }
d
:label3
/^--:/ ! {n;H;b label3 }
g;p"
cmd_fst="sed -ne '"`printf '%s\n' "$cmd_fst" | sed -e "s/'/$quch/g"`"'"
# fst word. make base output
# output block if center line is hit fstword
# p=-+1, fst=/b/
# ...
# --:
# 2:aaa
# 3:bbb
# 4:ccc
# --:
# 11:vvv
# 12:abc ...
# echo "$cmd_fst" >/dev/stderr
# sleep 10
# --+行番号で加工済みの群をふるいにかける。
# second or later word.
# remove --: and ck
buf="$#"
buf=$((buf - 1))
cmd_filter='cat -'
for ii in `seq 1 "$buf" `
do
set -- "$@" "$1"
shift
bufcmd="
:label1
h
:label2
/^--:/ d
s/^[0123456789]\{1,\}.//1
$ws1$1$ws2 ! { n;H; b label2 }
:label3
/^--:/ ! {n;H;b label3 }
g;p"
bufcmd="sed -ne '"`printf '%s\n' "$bufcmd" | sed -e "s/'/$quch/g" `"'"
cmd_filter=`printf '%s | %s' "$cmd_filter" "$bufcmd"`
done
# echo "$cmd_filter" >/dev/stderr
# sleep 10
set -- "$@" "$1"
shift
# echo "___$# $ws1"
# printf '%s\n@ %s\n @%s\n' "$cmd_stdin" "$cmd_fst" "$cmd_filter"
# exit
# dispname '\111\222\333'
dispfname(){
if [ "$opt_o" = "0" ] ; then
printf "'"
printf '%b//\n' "$1" | sed -e "s/[']/$quch/g" | sed -e "s#//#'#"
else
printf '%s\n' "$1"
fi
}
# output format 10:aaa ... -> 10: aaa, remove spliter if one word
if [ "$opt_p" = "0" ] ; then #one word
outfmt="sed -e 's/^[0123456789-]\{1,\}:/& /g' | sed -e 's/^--: //g' | grep -v '^$'"
else
outfmt="sed -e 's/^[0123456789-]\{1,\}:/& /g' | sed -e 's/^--: /--:/g'"
fi
# ここら辺でgnuとそれ以外を分割ってところ。
# file検索方法分け
# 行付き本文を整えてwordを追加検索
# cat file | comm_stream_func "\123\123"
func_rawline_input (){
eval "$cmd_split" | eval "$cmd_fst" |
eval "$cmd_filter" | sed -e 's#\(^[0123456789]\{1,\}\).#\1:#1' | eval "$outfmt" |
# \(\)は後方利用で\1に必要。
# ヒットして初めてファイル名と結果を出力。ファイル名はfuncで変換
( read -r A
if [ "$A" != "" ] ; then
dispfname "$1"
printf "%s\n" "$A"
cat -
echo
fi )
}
# single file
if [ "$sfile" != "./" ] ; then
octfile=`func_rlp "$sfile"`
cat "$sfile" | ( printf "$dmy" ; grep -n '' ; printf "$dmy" ) |
func_rawline_input "$octfile"
exit 0
fi
# multi file
if [ "$mposix" = "0" ] ; then
buf=$((opt_r + 1))
# 140ms eval ... pwdで単体80ms 深さ2とか5とか細かい指定がある場合。
findcmd=`cat << 'EEE'
find -L ./ -maxdepth $buf -type f -print0 |
xargs -0 -I aaa grep -Zle "$fstword" -- aaa
EEE
`
# pwdのみ。単体5ms程度
if [ "$opt_r" = "0" ] ; then
findcmd="grep -Zle "'"$fstword" -- * .* 2>/dev/null'
# glob() ... shell pattern. * doesnt get hiding file (.config.txt etc)
# grep is default BRE mode. -E uses ERE mode (posix)
fi
# 再帰。70ms eval ...単体10ms程度
if [ "$opt_r" = "-1" ] ; then # grepの高速検索
findcmd="grep -Zlre "'"$fstword" --'
fi
# fix. one file
if [ "$sfile" != "./" ] ; then # grepの高速検索
findcmd="grep -Zlre "'"$fstword" -- "$sfile"'
fi
# ここまで60ms 5ms程度の遅れだけど殆どさはない。
# file-filter. word kick
zfilter='cat -'
for ii in `seq 1 $#`
do
zfilter="$zfilter | xargs -0 grep -lZe \"\$$ii\" --"
done
# cat - | xargs -0 grep -lZe "$1" -- | xargs -0 grep -lZe "$2" --
# eval "$findcmd" | eval "$cmd_fulloct" ; exit
# findcmdの時点で+10ms. 単体は*系(grob検索)の方が圧倒的に早い。1msと5msで4msも早い。
eval "$findcmd" |
eval "$zfilter" |
# eval "$cmd_octal" |
eval "$cmd_fulloct" |
# fulloctはreadlink_gnuの有無で切り替える。あれば早いgnu.
# ここで105ms。 40ms遅れる。ファイルにフィルターをかけるか。>>絞っても変わらない
# fnsも100ms程度だった。+20ms. rlpのせいではないみたい。
# grep -lで絞っているのが効いているみたい。こっちも先に絞るか。
# むしろ遅くなった。130ms. 分からん。rdoptの差だとしとこ。 >> 嘘。はやくなった
# >>> 発見。やっぱりreadlinkっぽい。全部処理すると40ms増える。
# octal化のみだとそれが省略可能。結局毎回xargsで読み出すからオーバーヘッド
# がどんどん増えるみたい。後回しにしてみる
# 後回しでloopは逆転レベル。-10ms. fstwordが悪いのか?
# grepは大して遅くない。awkで弾いてもok. rawか。
# 同じfuncを使ってるのに30msも差が出る。
# rawでも同じぐらい30ms遅れる。ってことはrawは悪くない。
# レジスタとか環境のせい?
# ()から{}に変えてサブシェル以外にしても変化無し。
# whileの中身を処理にかけると途端に遅くなる。なぜ。
# while conならむしろ早いんだけど。
# whileに入る前にgrepfilterでファイルを絞れば早くなった。結局sedで5倍に増えてしまうから
# なるべく採用を絞った方が結果的に早くなる.
# 結果。whileに入る前にファイルを厳選する。fulloctはその後。ストリームで流した方が
# ovhが少ない。
while read -r octfile
do
file=`printf "$octfile"'@'`
file=${file%@}
( printf "$dmy"
grep -nC "$opt_p" -e "$fstword" -- "$file"
printf "$dmy" ) | awk '
$1 ~ /^[0123456789]/ {print $0}' | func_rawline_input "$octfile"
done
fi
if [ "$mposix" = "1" ] ; then
if [ "$opt_r" = "-1" ] ; then
# 基本的にはgnuと一緒だけど-Z系が無いのでその辺を補完。
# grepはlでファイルのみ。発見次第打ち切り。未発見でerrが返る。execを入れると劇的に遅くなる
# 後工程に任せる。gnuでも4msが131msに膨れ上がる。でもこれ以外に検索方法は無い。
# locate> posixではない。
# print0が10msでprintf \000は441ms
# posixでは\000ファイル出力ができないのでgrep絞りは後で。
# grepは-Zが無いので使用不可
findcmd="find -L ./ -type f -a -exec printf '%s\000' '{}' ';'"
else
ptn='*/*/*' #>> pwdは/一つだけ。//はサブディレクトリ。///はサブサブ。
for ii in `seq 1 $opt_r `
do
ptn="$ptn"'/*'
done
findcmd="find -L ./ -path '$ptn' -prune -o -type f -a -exec printf '%s\000' '{}' ';'"
fi
# fix. one file
if [ "$sfile" != "./" ] ; then # grepの高速検索
findcmd='cat "$sfile"'
fi
grep_cnt=''
for ii in `seq 1 $#`
do
grep_cnt="$grep_cnt grep -le \"\$$ii\" -- \"\$file\" ;"
done
grep_cnt="( $grep_cnt ) | wc -l"
# ( grep -le "$1" -- "$file" ; grep -le "$2" -- "$file" ; grep -le "$3" -- "$file" ; ) | wc -l
# マルチgrepの代用。一つのファイルに大して単語ごとに検索をかけてヒットを数える。
# \000が使えずストリーム処理が出来ないので、せめてもの抵抗。少しでも絞る。
# 3 wordなら3になるはず。小さければどれかの単語が入ってないのでスキップ。
#---main
eval "$findcmd" |
eval "$cmd_fulloct" |
# od -An -to1 -w16 -v |
# sed -e 's/ 000/@/g' | tr -d '\n' | tr ' ' '\134' |
# tr '@' '\n' |
while read -r octfile
do
file=`printf "$octfile"'@'`
file=${file%@}
buf=`eval "$grep_cnt"`
if [ "$buf" != "$#" ] ; then
continue
fi
# octfull=`printf "$file\000" | func_rlp` # fullpath.
# ファイルを絞ってから検査したい。10ms程度早い。微妙か。誤差範囲。むしろovhで遅い。
cat "$file" | ( printf "$dmy" ; grep -n '' ; printf "$dmy" ) |
func_rawline_input "$octfile"
done
fi