#!/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