Ctrl c linux script

How to handle Ctrl + c in shell script?

I am trying to handle the ctrl + c in the shell script. I have code running in while loop but i am calling the binary from script and running it in background so when i want to stop the binary should stop. Code is below of hello.c
vim hello.c

#/i/bin/sh echo run the hello binary ./hello < in.txt & trap_ctrlc() < ps -eaf | grep hello | grep -v grep | awk '' | xargs kill -9 echo trap_ctrlc exit > trap trap_ctrlc SIGHUP SIGINT SIGTERM 

After starting the script the hello binary is running continuously. I have killed this binary from other terminal using kill -9 pid command.
I have tried this trap_ctrlc function but it not work. How to handle the Ctrl + c in shell script. In in.txt i have added the input so i can pass this file directly to the binary
vim in.txt

Output:
Enter the first number
Enter the second number
Entered number are n1 = 1 , n2 =2
Enter the first number
Enter the second number
Entered number are n1 = 1 , n2 =2
Enter the first number
Enter the second number
Entered number are n1 = 1 , n2 =2
And it going continuously.

@TedLyngmo Thank you so much this works. I have one doubt if i ran say 2 or 3 binary in script then how to kill all binaries after hitting ctrl +c. And about the solution on script on line number 4 i am getting the error «Syntax error: «(» unexpected» The ‘function’ written before print_forever caused this issue. So i removed it.

kill -9 is SIGKILL, you can’t trap SIGKILL. See: man7.org/linux/man-pages/man7/signal.7.html You could try kill -HUP and just plain kill .

1 Answer 1

Change your c program so it checks if reading data actually succeeded:

It will now terminate when the input from in.txt is depleted.

To make something that reads from in.txt many times, you could create a loop in your bash script that feeds ./hello forever (or until it’s killed).

#!/bin/bash # a function to repeatedly print the content in "in.txt" function print_forever() < while [ 1 ]; do cat "$1" sleep 1 done >echo run the hello binary print_forever in.txt | ./hello & pid=$! echo "background process $pid started" trap_ctrlc() < kill $pid echo -e "\nkill=$? (0 = success)\n" wait $pid echo "wait=$? (the exit status from the background process)" echo -e "\n\ntrap_ctrlc\n\n" >trap trap_ctrlc INT # wait for all background processes to terminate wait 
$ ./hello.sh run the hello binary background process 262717 started Enter the first number Enter the second number Entered number are n1 = 1 , n2 =2 Enter the first number Enter the second number Entered number are n1 = 1 , n2 =2 Enter the first number ^C kill=0 (0 = success) wait=143 (the exit status from the background process) trap_ctrlc 

Another option can be to kill the child after the wait is interrupted:

#!/bin/bash function print_forever() < while [ 1 ]; do cat "$1" sleep 1 done >echo run the hello binary print_forever in.txt | ./hello & pid=$! echo "background process $pid started" trap_ctrlc() < echo -e "\n\ntrap_ctrlc\n\n" >trap trap_ctrlc INT # wait for all background processes to terminate wait echo first wait=$? kill $pid echo -e "\nkill=$? (0 = success)\n" wait $pid echo "wait=$? (the exit status from the background process)"` `` 

Источник

Читайте также:  Create file with linux command

How to send control+c from a bash script?

I’m starting a number of screens in a bash script, then running django’s runserver command in each of them. I’d like to be able to programmatically stop them all as well, which requires me to send Control+c to runserver . How can I send these keystrokes from my bash script?

5 Answers 5

Ctrl+C sends a SIGINT signal.

kill -INT sends a SIGINT signal too:

# Terminates the program (like Ctrl+C) kill -INT 888 # Force kill kill -9 888 

Assuming 888 is your process ID.

Note that kill 888 sends a SIGTERM signal, which is slightly different, but will also ask for the program to stop. So if you know what you are doing (no handler bound to SIGINT in the program), a simple kill is enough.

To get the PID of the last command launched in your script, use $! :

# Launch script in background ./my_script.sh & # Get its PID PID=$! # Wait for 2 seconds sleep 2 # Kill it kill $PID 

⚠️ ctrl + c is not exactly the same as kill -SIGINT . The former sends the INT signal to the group and the later only to the given . See this question.

CTRL-C generally sends a SIGINT signal to the process so you can simply do:

from the command line (or a script), to affect the specific processID .

I say «generally» because, as with most of UNIX, this is near infinitely configurable. If you execute stty -a , you can see which key sequence is tied to the intr signal. This will probably be CTRL-C but that key sequence may be mapped to something else entirely.

The following script shows this in action (albeit with TERM rather than INT since sleep doesn’t react to INT in my environment):

#!/usr/bin/env bash sleep 3600 & pid=$! sleep 5 echo === echo PID is $pid, before kill: ps -ef | grep -E "PPID|$pid" | sed 's/^/ /' echo === ( kill -TERM $pid ) 2>&1 sleep 5 echo === echo PID is $pid, after kill: ps -ef | grep -E "PPID|$pid" | sed 's/^/ /' echo === 

It basically starts an hour-log sleep process and grabs its process ID. It then outputs the relevant process details before killing the process.

After a small wait, it then checks the process table to see if the process has gone. As you can see from the output of the script, it is indeed gone:

=== PID is 28380, before kill: UID PID PPID TTY STIME COMMAND pax 28380 24652 tty42 09:26:49 /bin/sleep === ./qq.sh: line 12: 28380 Terminated sleep 3600 === PID is 28380, after kill: UID PID PPID TTY STIME COMMAND === 

Источник

Читайте также:  Ftp server on linux mint

Linux — Send Ctrl+C using linux/bash commands for specific shell script

I have written a shell script which processes a text input and displays the expected output, but post displaying the expected result — it waits for a ctrl+c in order for it to complete and for cursor to move to $_ space. How can I include this ctrl+c in my shell script itself ? or what is the shell script that does ctrl+c using bash/shell commands ? The script is as follows: sed ‘s/\xC2\xA0//g’ | awk ‘$1==»|»else>’ filename.txt filename.txt contains: https://justpaste.it/edit/30310895/df1838c844c0fcd1

Your script should just exit after the job is done. There must be something wrong with your script, you should post it here.

What does the script do after it has processed the input, and how does it process the input? Please post the script in your question.

@dynamicJos what do you need sed for? It doesn’t do anything at all here. Just remove sed ‘s/\xC2\xA0//g’ | from your script.

2 Answers 2

The pipeline that you show is essentially

sed expression | awk expression filename 

This would run awk on the file filename while sed would sit around doing nothing while waiting for input from the user on its standard input (it would read what you typed on the terminal at that point).

To exit this script, you simply press Ctrl+D to signal the end of input to the sed process. When sed notices that there will be nothing more to read, it terminates and the script exits (since that was what was «pausing» it).

Your current script is more or less equivalent of running

awk expression filename sed expression 

. since the two commands are not communicating with each other over the pipe.

What you want to be doing is

sed expression filename | awk expression 

Here, sed is operating on the file and sends the result over to awk for further processing. awk is started without a filename, which means it reads from its standard input, which is connected to the standard output of sed via the pipe.

sed 's/\xC2\xA0//g' filename.txt | awk '$1=="|"else>' 

(If that pipeline does what you want it to do or not, I don’t know, but now at least the sed and awk processes would be piped correctly).

Источник

How can bash script do the equivalent of Ctrl-C to a background task?

Is there any way to invoke a subprocess so that it and all its descendants are sent an interrupt, just as if you Ctrl-C a foreground task? I’m trying to kill a launcher script that invokes a long-running child. I’ve tried kill -SIGINT $child (which doesn’t send the interrupt to its descendants so is a no-op) and kill -SIGINT -$child (which works when invoked interactively but not when running in a script). Here’s a test script. The long-running script is test.sh —child . When you call test.sh —parent , it invokes test.sh —child & and then tries to kill it. How can I make the parent kill the child successfully?

#!/bin/bash if [ "$1" = "--child" ]; then sleep 1000 elif [ "$1" = "--parent" ]; then "$0" --child & for child in $(jobs -p); do echo kill -SIGINT "-$child" && kill -SIGINT "-$child" done wait $(jobs -p) else echo "Must be invoked with --child or --parent." fi 

I know that you can modify the long-running child to trap signals, send them to its subprocess, and then wait (from Bash script kill background (grand)children on Ctrl+C), but is there any way without modifying the child script?

Читайте также:  Linux запуск терминала от имени администратора

4 Answers 4

For anyone wondering, this is how you launch childs in the background and kill them on ctrl+c:

#!/usr/bin/env bash command1 & pid[0]=$! command2 & pid[1]=$! trap "kill $ $; exit 1" INT wait 

This is useful, although I found that kill would only kill the processes specified in the arguments, and not their descendants.

 To facilitate the implementation of the user interface to job control, the operating system maintains the notion of a current terminal process group ID. Members of this process group (processes whose process group ID is equal to the current terminal process group ID) receive keyboard- generated signals such as SIGINT. These processes are said to be in the foreground. Background processes are those whose process group ID differs from the terminal's; such processes are immune to keyboard-gen‐ erated signals. 

So bash differentiates background processes from foreground processes by the process group ID. If the process group id is equal to process id, then the process is a foreground process, and will terminate when it receives a SIGINT signal. Otherwise it will not terminate (unless it is trapped).

You can see the process group Id with

Thus, when you run a background process (with & ) from within a script, it will ignore the SIGINT signal, unless it is trapped.

However, you can still kill the child process with other signals, such as SIGKILL , SIGTERM , etc.

For example, if you change your script to the following it will successfully kill the child process:

#!/bin/bash if [ "$1" = "--child" ]; then sleep 1000 elif [ "$1" = "--parent" ]; then "$0" --child & for child in $(jobs -p); do echo kill "$child" && kill "$child" done wait $(jobs -p) else echo "Must be invoked with --child or --parent." fi 
$ ./test.sh --parent kill 2187 ./test.sh: line 10: 2187 Terminated "$0" --child 

Источник

Оцените статью
Adblock
detector