在while循环体内使用sqlcmd时无限循环。

huangapple go评论69阅读模式
英文:

looping infinitely when using sqlcmd inside a while-loop body

问题

以下是您提供的bash脚本的翻译部分:

我有一个bash脚本,其中使用`sqlcmd`从数据库中获取数据,并在**while循环**中执行:

#!/bin/bash
tmpfile=$(mktemp)
echo -e "1\n2" > tmpfile
echo "---------------来自临时文件的内容--------------"
cat tmpfile
echo "------------------------------------------------------"
while read -r line || [[ -n $line ]]
do
  echo "${line}"
  echo "   ------------sqlcmd操作开始------------"
  sqlcmd -Q "set nocount on;select 'dummy'"  < /dev/null
  echo -e "   ------------sqlcmd操作完成------------\n\n"
done < tmpfile
echo "-----------------------脚本完成---------------------"

脚本期望根据文件.txt中的内容行进行迭代,例如在此情况下是两次,但实际上它会无限迭代第一行。

您提到了如何解决无限循环的答案,您可以在这里找到解决方法。

请注意,此翻译仅包括脚本的部分,不包括问题或注释。如果您需要进一步的翻译或有其他问题,请告诉我。

英文:

I have a bash script which uses sqlcmd for fetching data from database in a while-loop body:

#!/bin/bash
tmpfile=$(mktemp)
echo -e &quot;1\n2&quot; &gt; tmpfile
echo &quot;---------------content from the tmp file--------------&quot;
cat tmpfile
echo &quot;------------------------------------------------------&quot;
while read -r line || [[ -n $line ]]
do
  echo &quot;${line}&quot;
  echo &quot;   ------------sqlcmd operation start------------&quot;
  sqlcmd -Q &quot;set nocount on;select &#39;dummy&#39;&quot;  
  echo -e &quot;   ------------sqlcmd operation done------------\n\n&quot;
done &lt; tmpfile
echo &quot;-----------------------script done---------------------&quot;

It is expected to interate based on the line of content in the file.txt, that is twice in this cases, but acutally it will interate the first line infinitely:
在while循环体内使用sqlcmd时无限循环。

I got the anwser about how to resolve the infinite loop from here loop variables stuck as constant when using sqlcmd

and here Unexpected behavior of file descriptor and/or I/O streams after running sqlcmd with -i option (read sql from file) in ksh creates infinite loop.

Simply put, it can be resolved if we redirect the input stream, for example:

#!/bin/bash
tmpfile=$(mktemp)
echo -e &quot;1\n2&quot; &gt; tmpfile
echo &quot;---------------content from the tmp file--------------&quot;
cat tmpfile
echo &quot;------------------------------------------------------&quot;
while read -r line || [[ -n $line ]]
do
  echo &quot;${line}&quot;
  echo &quot;   ------------sqlcmd operation start------------&quot;
  sqlcmd -Q &quot;set nocount on;select &#39;dummy&#39;&quot; &lt; /dev/null  
  echo -e &quot;   ------------sqlcmd operation done------------\n\n&quot;
done &lt; tmpfile
echo &quot;-----------------------script done---------------------&quot;

在while循环体内使用sqlcmd时无限循环。

Below script which is just replace sqlcmd with other command, e.g. date then it is normal. I think it can prove this issue is relative to sqlcmd:

#!/bin/bash
tmpfile=$(mktemp)
echo -e &quot;1\n2&quot; &gt; tmpfile
echo &quot;---------------content from the tmp file--------------&quot;
cat tmpfile
echo &quot;------------------------------------------------------&quot;
while read -r line || [[ -n $line ]]
do
  echo &quot;${line}&quot;
  echo &quot;   ------------sqlcmd operation start------------&quot;
  #sqlcmd -Q &quot;set nocount on;select &#39;dummy&#39;&quot;
  date
  echo -e &quot;   ------------sqlcmd operation done------------\n\n&quot;
done &lt; tmpfile
echo &quot;-----------------------script done---------------------&quot;

在while循环体内使用sqlcmd时无限循环。

More interesting, if the content of the file is less than 4 charaters(including invisible char), it woudn't cause infinite iteration:

#!/bin/bash
tmpfile=$(mktemp)
#less than 4 char -- normal
echo -ne &quot;123&quot; &gt; tmpfile
echo &quot;---------------content from the tmp file--------------&quot;
cat tmpfile
echo &quot;------------------------------------------------------&quot;
while read -r line || [[ -n $line ]]
do
  echo &quot;${line}&quot;
  echo &quot;   ------------sqlcmd operation start------------&quot;
  sqlcmd -Q &quot;set nocount on;select &#39;dummy&#39;&quot;
  #date
  echo -e &quot;   ------------sqlcmd operation done------------\n\n&quot;
done &lt; tmpfile
echo &quot;-----------------------script done---------------------&quot;

在while循环体内使用sqlcmd时无限循环。

Infinite when there is more than 3 charaters:

#!/bin/bash
tmpfile=$(mktemp)
#more than 3 chars -- infinite
echo -ne &quot;1234&quot; &gt; tmpfile
echo &quot;---------------content from the tmp file--------------&quot;
cat tmpfile
echo &quot;------------------------------------------------------&quot;
while read -r line || [[ -n $line ]]
do
  echo &quot;${line}&quot;
  echo &quot;   ------------sqlcmd operation start------------&quot;
  sqlcmd -Q &quot;set nocount on;select &#39;dummy&#39;&quot;
  #date
  echo -e &quot;   ------------sqlcmd operation done------------\n\n&quot;
done &lt; tmpfile
echo &quot;-----------------------script done---------------------&quot;

在while循环体内使用sqlcmd时无限循环。

All in all, I'm curious how sqlcmd leads to the infinite looping.
I can understand that the sqlcmd inherits the input stream from the outsiede while loop, and as it inhereists the input stream, if it slurps the conent then it should lead to less iteration for the outside while loop, but how it is possible cause looping infinitely?

答案1

得分: 5

My best guess is that sqlcmd uses lseek to set the file offset for its standard input back to the start of the file. Certainly, doing that would cause the infinite loop problem. This Shellcheck-clean code uses perl to reproduce the problem:

#! /bin/bash -p

while read -r line || [[ -n $line ]]; do
    printf '%s\n' "$line"
    perl -e 'seek(STDIN, 0, 0)'
done <"${BASH_SOURCE[0]}"

Running a file containing this code with Bash generates output:

#! /bin/bash -p
#! /bin/bash -p
#! /bin/bash -p
...

until it is interrupted.

One way to verify this theory would be to run the shell program with strace (strace -f -o strace.out SHELLPROG). I expect the output to include something like this for the sqlcmd process:

... lseek(0, 0, SEEK_SET) = 0
英文:

My best guess is that sqlcmd uses lseek to set the file offset for its standard input back to the start of the file. Certainly, doing that would cause the infinite loop problem. This Shellcheck-clean code uses perl to reproduce the problem:

#! /bin/bash -p

while read -r line || [[ -n $line ]]; do
    printf &#39;%s\n&#39; &quot;$line&quot;
    perl -e &#39;seek(STDIN, 0, 0)&#39;
done &lt;&quot;${BASH_SOURCE[0]}&quot;

Running a file containing this code with Bash generates output

#! /bin/bash -p
#! /bin/bash -p
#! /bin/bash -p
...

until it is interrupted.

One way to verify this theory would be to run the shell program with strace (strace -f -o strace.out SHELLPROG). I expect the output to include something like this for the sqlcmd process:

... lseek(0, 0, SEEK_SET)           = 0

huangapple
  • 本文由 发表于 2023年4月17日 16:49:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76033294.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定