Shell 脚本帮助——接受输入并在后台运行?

发布于 2024-11-29 07:44:05 字数 1236 浏览 1 评论 0原文

我有一个 shell 脚本,在第一行中,我要求用户输入他们希望脚本运行多少分钟:

 #!/usr/bin/ksh
echo "How long do you want the script to run for in minutes?:\c"
read scriptduration
loopcnt=0
interval=1
date2=$(date +%H:%M%S)
(( intervalsec = $interval * 1 ))
totalmin=${1:-$scriptduration}
(( loopmax = ${totalmin} * 60 ))

ofile=/home2/s499929/test.log
echo "$date2 total runtime is $totalmin minutes at 2 sec intervals"
while(( $loopmax > $loopcnt ))
do
  date1=$(date +%H:%M:%S)
   pid=`/usr/local/bin/lsof | grep 16752 | grep LISTEN |awk '{print $2}'` > /dev/null 2>&1
   count=$(netstat -an|grep 16752|grep ESTABLISHED|wc -l| sed "s/ //g")
   process=$(ps -ef | grep $pid | wc -l | sed "s/ //g")
   port=$(netstat -an | grep 16752 | grep LISTEN | wc -l| sed "s/ //g")
  echo "$date1 activeTCPcount:$count activePID:$pid activePIDcount=$process listen=$port" >> ${ofile}
  sleep $intervalsec
  (( loopcnt = loopcnt + 1 ))
done

如果我手动输入值,效果会很好。但如果我想运行 3 个小时,我需要启动脚本在后台运行。

我尝试过只运行 ./scriptname &我明白了:

$ How long do you want the test to run for in minutes:360
ksh: 360:  not found.
[2] + Stopped (SIGTTIN)        ./test.sh &

剧本就死了。这可能吗,关于如何接受这一输入然后在后台运行有什么建议吗?谢谢!!!

I have a shell script in which in the first line I ask the user to input how many minutes they want the script to run for:

 #!/usr/bin/ksh
echo "How long do you want the script to run for in minutes?:\c"
read scriptduration
loopcnt=0
interval=1
date2=$(date +%H:%M%S)
(( intervalsec = $interval * 1 ))
totalmin=${1:-$scriptduration}
(( loopmax = ${totalmin} * 60 ))

ofile=/home2/s499929/test.log
echo "$date2 total runtime is $totalmin minutes at 2 sec intervals"
while(( $loopmax > $loopcnt ))
do
  date1=$(date +%H:%M:%S)
   pid=`/usr/local/bin/lsof | grep 16752 | grep LISTEN |awk '{print $2}'` > /dev/null 2>&1
   count=$(netstat -an|grep 16752|grep ESTABLISHED|wc -l| sed "s/ //g")
   process=$(ps -ef | grep $pid | wc -l | sed "s/ //g")
   port=$(netstat -an | grep 16752 | grep LISTEN | wc -l| sed "s/ //g")
  echo "$date1 activeTCPcount:$count activePID:$pid activePIDcount=$process listen=$port" >> ${ofile}
  sleep $intervalsec
  (( loopcnt = loopcnt + 1 ))
done

It works great if I kick it off an input the values manually. But if I want to run this for 3 hours I need to kick off the script to run in the background.

I have tried just running ./scriptname & and I get this:

$ How long do you want the test to run for in minutes:360
ksh: 360:  not found.
[2] + Stopped (SIGTTIN)        ./test.sh &

And the script dies. Is this possible, any suggestions on how I can accept this one input and then run in the background?? Thanks!!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

瑶笙 2024-12-06 07:44:05

你可以这样做:

test.sh arg1 arg2 &

只需将 arg1arg2 分别引用为 $1$2,在bash 脚本。 ($0 是脚本的名称)

因此,

test.sh 360 &

会将 360 作为第一个参数传递给 bash 或 ksh 脚本,在脚本中可以将其称为 $1

所以你的脚本的前几行现在是:

#!/usr/bin/ksh
scriptduration=$1
loopcnt=0
...
...

You could do something like this:

test.sh arg1 arg2 &

Just refer to arg1 and arg2 as $1 and $2, respectively, in the bash script. ($0 is the name of the script)

So,

test.sh 360 &

will pass 360 as the first argument to the bash or ksh script which can be referred to as $1 in the script.

So the first few lines of your script would now be:

#!/usr/bin/ksh
scriptduration=$1
loopcnt=0
...
...
靑春怀旧 2024-12-06 07:44:05

使用 bash,您可以在前台启动脚本,完成用户输入后,按 Ctrl-Z 中断它。

然后输入

$ bg %

,脚本将继续在后台运行。

With bash you can start the script in the foreground and after you finished with the user input, interrupt it by hitting Ctrl-Z.

Then type

$ bg %

and the script will continue to run in the background.

诠释孤独 2024-12-06 07:44:05

为什么您会得到您所得到的结果

当您在后台运行脚本时,它无法接受任何用户输入。事实上,如果程序需要用户输入,它将冻结,直到它被放回前台。然而,输出必须到达某个地方。因此,输出会显示到屏幕上(即使程序在后台运行。因此,您会看到提示符。

您看到程序显示的提示符是没有意义的,因为您无法在提示符下输入。相反,您输入360 并且您的 shell 会将其解释为您想要的命令,因为您没有将其放入程序中,而是将其放入命令提示符中

您希望程序位于前台 。输入,但在后台运行。无法同时执行这两项

操作

。您可以有两个程序,第一个程序接受输入,第二个程序在后台运行实际程序

#! /bin/ksh
read time?"How long in seconds do you want to run the job? "
my_actual_job.ksh $time &

事实上,您甚至可以有一个运行机制。如果时间超过一定限制,则作业在后台运行,但否则在前台运行作业。

#! /bin/ksh

readonly MAX_FOREGROUND_TIME=30
read time?"How long in seconds do you want to run the job? "
if [ $time -gt $MAX_FOREGROUND_TIME ]
then
    my_actual_job.ksh $time &
else
    my_actual_job.ksh $time
fi

另请记住,如果您的作业在后台,则它无法打印到屏幕,您可以将输出重定向到其他地方。不,它会打印到屏幕上不合时宜的时候。例如,您可能正在 VI 中编辑文件,突然输出出现在 VI 会话的中间。

我相信有一种简单的方法可以判断您的工作是否在后台,但我无法立即记住它。您可以通过查看 $$ 找到当前的进程 ID,然后查看 jobs -p 的输出并查看该进程 ID 是否在列表中。不过,我相信有人会想出一个简单的方法来区分。

程序也有可能通过 bg $$ 命令将自身置于后台。

一些提示

如果您正在运行 Kornshell,您可能会考虑利用 Kornshell 的许多特殊功能:

  • printprint 命令比 <代码>回显。查看 Kornshell 的联机帮助页并了解其所有功能。

  • read:您注意到可以使用读取命令的 read var?"prompt" 形式。

  • readonly:使用readonly声明常量。这样,您以后就不会意外更改该变量的值。此外,这是很好的编程技术。

  • typeset:查看 ksh 联机帮助页中的 typesettypeset 命令可以帮助您将特定变量声明为浮点与实数,并且可以自动执行诸如零填充、右对齐或左对齐等操作。

一些非 Kornshell 特有的操作:

  • awksed 命令也可以执行 grep 的操作,因此没有理由通过 grep 过滤某些内容,然后通过 awk 或sed

  • 您可以使用-e参数组合grep。 grep foo | | grep foo | grep foo | grep foo | grep foo | grep foo grep bar 与 grep -e foo -e bar 相同。

希望这有帮助。

Why You're Getting What You're Getting

When you run the script in the background, it can't take any user input. In fact, the program will freeze if it expects user input until its put back in the foreground. However, output has to go somewhere. Thus, the output goes to the screen (even though the program is running in the background. Thus, you see the prompt.

The prompt you see your program displaying is meaningless because you can't input at the prompt. Instead, you type in 360 and your shell is interpreting it as a command you want because you're not putting it in the program, you're putting it in the command prompt.

You want your program to be in the foreground for the input, but run in the background. You can't do both at once.

Solutions To Your Dilemma

You can have two programs. The first takes the input, and the second runs the actual program in the background.

Something like this:

#! /bin/ksh
read time?"How long in seconds do you want to run the job? "
my_actual_job.ksh $time &

In fact, you could even have a mechanism to run the job in the background if the time is over a certain limit, but otherwise run the job in the foreground.

#! /bin/ksh

readonly MAX_FOREGROUND_TIME=30
read time?"How long in seconds do you want to run the job? "
if [ $time -gt $MAX_FOREGROUND_TIME ]
then
    my_actual_job.ksh $time &
else
    my_actual_job.ksh $time
fi

Also remember if your job is in the background, it cannot print to the screen. You can redirect the output elsewhere, but if you don't, it'll print to the screen at inopportune times. For example, you could be in VI editing a file, and suddenly have the output appear smack in the middle of your VI session.

I believe there's an easy way to tell if your job is in the background, but I can't remember it offhand. You could find your current process ID by looking at $$, then looking at the output of jobs -p and see if that process ID is in the list. However, I'm sure someone will come up with an easy way to tell.

It is also possible that a program could throw itself into the background via the bg $$ command.

Some Hints

If you're running Kornshell, you might consider taking advantage of many of Kornshell's special features:

  • print: The print command is more flexible and robust than echo. Take a look at the manpage for Kornshell and see all of its features.

  • read: You notice that you can use the read var?"prompt" form of the read command.

  • readonly: Use readonly to declare constants. That way, you don't accidentally change the value of that variable later. Besides, it's good programming technique.

  • typeset: Take a look at typeset in the ksh manpage. The typeset command can help you declare particular variables as floating point vs. real, and can automatically do things like zero fill, right or left justify, etc.

Some things not specific to Kornshell:

  • The awk and sed commands can also do what grep does, so there's no reason to filter something through grep and then through awk or sed.

  • You can combine greps by using the -e parameter. grep foo | grep bar is the same as grep -e foo -e bar.

Hope this helps.

治碍 2024-12-06 07:44:05

我已经用 ksh 测试过它并且有效。诀窍是让脚本以等待时间作为参数来调用自身:

if [ -z "$1" ]; then
    echo "How long do you want the test to run for in minutes:\c"
    read scriptduration
    echo "running task in background"
    $0 $scriptduration &
    exit 0
else
    scriptduration=$1
fi

loopcnt=0
interval=1
# ... and so on

I've tested this with ksh and it worked. The trick is to let the script call itself with the time to wait as parameter:

if [ -z "$1" ]; then
    echo "How long do you want the test to run for in minutes:\c"
    read scriptduration
    echo "running task in background"
    $0 $scriptduration &
    exit 0
else
    scriptduration=$1
fi

loopcnt=0
interval=1
# ... and so on
我不在是我 2024-12-06 07:44:05

那么你使用的是bash还是ksh?在 bash 中,您可以这样做:

{ echo 360 | ./test.sh ; } &

它也适用于 ksh。

So are you using bash or ksh? In bash, you can do this:

{ echo 360 | ./test.sh ; } &

It could work for ksh also.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文