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" 100
100は、一度に処理する行数で実行します。