コマンドにパイプするためにファイルを分割する方法(stdoutに分割するなど)は何ですか?

コマンドにパイプするためにファイルを分割する方法(stdoutに分割するなど)は何ですか?

SQL Serverデータベースにデータを挿入したいステートメント.sqlでいっぱいの大容量ファイルがあります。SELECTデフォルトでは、一度に100行ずつファイルの内容を取得し、残りのタスクを実行するように設定したコマンドに渡す方法を探しています。

デフォルトでは、ファイルではなくsplit出力を入れようとします。stdout

また、WindowsでCygWinを使用しているため、ツールバー全体にアクセスできません。

答え1

最も簡単な方法は次のとおりです。

while IFS= read -r line; do
  { printf '%s\n' "$line"; head -n 99; } |
  other_commands
done <database_file

readファイルの終わりに達すると停止する他の方法がないようですので、各セクションの最初の行に使用する必要があります。詳細については、次を参照してください。

答え2

デフォルトでは、ファイルではなくsplit出力を入れようとします。stdout

アクセス権がある場合、gnu splitこの--filterオプションは正確に次のことを行います。

‘--filter=command’

    With this option, rather than simply writing to each output file, write
    through a pipe to the specified shell command for each output file.

--filterしたがって、お客様の場合は、次のコマンドを使用できます。

split -l 100 --filter='{ cat Header.sql; cat; } | sqlcmd; printf %s\\n DONE' infile

または、次のスクリプトを作成してくださいmyscript

#!/bin/sh

{ cat Header.sql; cat; } | sqlcmd
printf %s\\n '--- PROCESSED ---'

その後、単に実行してください。

split -l 100 --filter=./myscript infile

答え3

_linc() ( ${sh-da}sh ${dbg+-vx} 4<&0 <&3 ) 3<<-ARGS 3<<\CMD
        set -- $( [ $((i=${1%%*[!0-9]*}-1)) -gt 1 ] && {
                shift && echo "\${inc=$i}" ; }
        unset cmd ; [ $# -gt 0 ] || cmd='echo incr "#$((i=i+1))" ; cat'
        printf '%s ' 'me=$$ ;' \
        '_cmd() {' '${dbg+set -vx ;}' "$@" "$cmd" '
        }' )
        ARGS
        s= ; sed -f - <<-INC /dev/fd/4 | . /dev/stdin
                i_cmd <<"${s:=${me}SPLIT${me}}"
                ${inc:+$(printf '$!n\n%.0b' `seq $inc`)}
                a$s
        INC
CMD

上記の関数は、sed引数リストをコマンド文字列として任意の行増分に適用するために使用されます。コマンドラインで指定したコマンドは一時シェル関数に入力され、これは各増分のステップ行を含むここのstdinのドキュメントに入力されます。

次のように使用します。

time printf 'this is line #%d\n' `seq 1000` |
_linc 193 sed -e \$= -e r \- \| tail -n2
    #output
193
this is line #193
193
this is line #386
193
this is line #579
193
this is line #772
193
this is line #965
35
this is line #1000
printf 'this is line #%d\n' `seq 1000`  0.00s user 0.00s system 0% cpu 0.004 total

ここでのメカニズムは非常に簡単です。

i_cmd <<"${s:=${me}SPLIT${me}}"
${inc:+$(printf '$!n\n%.0b' `seq $inc`)}
a$s

これがsedスクリプトです。基本的に私たちはちょうどprintf $increment * n;。したがって、増分を100に設定すると、100行のスクリプトをprintf作成しますsed。つまり$!n、1行はinsertここの文書の上部に、もう1行はappend文書の下部に使用されます。それがすべてです。残りのほとんどは処理オプションです。

extコマンドは、現在の行を印刷して削除し、次の行を取得するようにn指示します。最後の行を除くすべての行のみを試行するようにsed指定します。$!

1つの増分器のみが提供され、これは次のことを行います。

printf 'this is line #%d\n' `seq 10` |                                  ⏎
_linc 3
    #output
incr #1
this is line #1
this is line #2
this is line #3
incr #2
this is line #4
this is line #5
this is line #6
incr #3
this is line #7
this is line #8
this is line #9
incr #4
this is line #10

したがって、後で行われることは、関数がechoカウンタとcat入力(コマンド文字列が指定されていない場合)に設定されることです。コマンドラインから見ると、次のようになります。

{ echo "incr #$((i=i+1))" ; cat ; } <<HEREDOC
this is line #7
this is line #8
this is line #9
HEREDOC

各増分ごとにこれらのいずれかを実行します。望むより:

printf 'this is line #%d\n' `seq 10` |
dbg= _linc 3
    #output
set -- ${inc=2}
+ set -- 2
me=$$ ; _cmd() { ${dbg+set -vx ;} echo incr "#$((i=i+1))" ; cat
}
+ me=19396
        s= ; sed -f - <<-INC /dev/fd/4 | . /dev/stdin
                i_cmd <<"${s:=${me}SPLIT${me}}"
                ${inc:+$(printf '$!n\n%.0b' `seq $inc`)}
                a$s
        INC
+ s=
+ . /dev/stdin
+ seq 2
+ printf $!n\n%.0b 1 2
+ sed -f - /dev/fd/4
_cmd <<"19396SPLIT19396"
this is line #1
this is line #2
this is line #3
19396SPLIT19396
+ _cmd
+ set -vx ; echo incr #1
+ cat
this is line #1
this is line #2
this is line #3
_cmd <<"19396SPLIT19396"

とても速い

time yes | sed = | sed -n 'p;n' |
_linc 4000 'printf "current line and char count\n"
    sed "1w /dev/fd/2" | wc -c
    [ $((i=i+1)) -ge 5000 ] && kill "$me" || echo "$i"'

    #OUTPUT

current line and char count
19992001
36000
4999
current line and char count
19996001
36000
current line and char count
[2]    17113 terminated  yes |
       17114 terminated  sed = |
       17115 terminated  sed -n 'p;n'
yes  0.86s user 0.06s system 5% cpu 16.994 total
sed =  9.06s user 0.30s system 55% cpu 16.993 total
sed -n 'p;n'  7.68s user 0.38s system 47% cpu 16.992 total

上記では4000行ごとに増加するよう指示しました。 17秒後に2000万行を処理しました。もちろん、論理は厳密ではありません。各行を2回読み、すべての文字を数えるだけです。しかし、可能性はかなり開いています。また、詳細を見ると、ほとんどの時間を占めるように見える入力を提供するフィルタであることがわかります。

答え4

私はかなり嫌なように見える結果を得ました。もっと良い方法があれば投稿してください:

#!/bin/sh

DONE=false
until $DONE; do
    for i in $(seq 1 $2); do 
        read line || DONE=true;
        [ -z "$line" ] && continue;
        lines+=$line$'\n';
    done
    sql=${lines::${#lines}-10}
    (cat "Header.sql"; echo "$sql";) | sqlcmd
    #echo "--- PROCESSED ---";
    lines=;
done < $1

./insert.sh "File.sql" 100100は、一度に処理する行数で実行します。

関連情報