Jump to the next function by pressing Ctrl-C - bash

Assume that there are some functions which they do different jobs. I want to be able to press Ctrl-C to jump to the next function instead of canceling all the script at once.
I tried trap ctrl_c INT but it didn't work. FYI, I use curl in some of the functions.
How can I do it?
function first {
# do the first job
}
function second {
# do the second job
}
function third {
# do the third job
}
first &&
second &&
third &&
rm *.del

Hooking Ctrl+C to return 0 seems to work fine. Like:
# define first, second, and third here
trap 'return 0' INT
first &&
second &&
third &&
trap - INT &&
rm *.del

Related

Bash - exit does not exit script (only subshell) [duplicate]

How would you exit out of a function if a condition is true without killing the whole script, just return back to before you called the function.
Example
# Start script
Do scripty stuff here
Ok now lets call FUNCT
FUNCT
Here is A to come back to
function FUNCT {
if [ blah is false ]; then
exit the function and go up to A
else
keep running the function
fi
}
Use:
return [n]
From help return
return: return [n]
Return from a shell function.
Causes a function or sourced script to exit with the return value
specified by N. If N is omitted, the return status is that of the
last command executed within the function or script.
Exit Status:
Returns N, or failure if the shell is not executing a function or script.
Use return operator:
function FUNCT {
if [ blah is false ]; then
return 1 # or return 0, or even you can omit the argument.
else
keep running the function
fi
}
If you want to return from an outer function with an error without exiting you can use this trick:
do-something-complex() {
# Using `return` here would only return from `fail`, not from `do-something-complex`.
# Using `exit` would close the entire shell.
# So we (ab)use a different feature. :)
fail() { : "${__fail_fast:?$1}"; }
nested-func() {
try-this || fail "This didn't work"
try-that || fail "That didn't work"
}
nested-func
}
Trying it out:
$ do-something-complex
try-this: command not found
bash: __fail_fast: This didn't work
This has the added benefit/drawback that you can optionally turn off this feature: __fail_fast=x do-something-complex.
Note that this causes the outermost function to return 1.
My use case is to run the function unless it's already running. I'm doing
mkdir /tmp/nice_exit || return 0
And then at the end of the function
rm -rf /tmp/nice_exit

Golang switch statement only calls function once

I encountered a rather strange bug writing a program in Go.
Essentially, I have a switch statement where each case is supposed to call a function, setill, twice. But when the relevant case runs, it only calls the function once.
Here's the code snippet:
check := true
n, e, s, w := b.North, b.East, b.South, b.West
switch {
// NE (>)
case n.Closed && e.Closed:
check = check && p.setIll(s)
check = check && p.setIll(w)
// NS (\\)
case n.Closed && s.Closed:
check = check && p.setIll(e)
check = check && p.setIll(w)
// NW (^)
case n.Closed && w.Closed:
check = check && p.setIll(e)
check = check && p.setIll(s)
// ES (v)
case e.Closed && s.Closed:
check = check && p.setIll(n)
check = check && p.setIll(w)
// EW (//)
case e.Closed && w.Closed:
fmt.Println("Running setIll the first time")
check = check && p.setIll(n)
fmt.Println("Running it again")
check = check && p.setIll(s)
fmt.Println("And now we're done running")
// SW (<)
case s.Closed && w.Closed:
check = check && p.setIll(n)
check = check && p.setIll(e)
}
Here's setIll:
func (p Player) setIll(n *Node) bool {
fmt.Println("I'm running!")
p.Illegal.Nodes[n.Loc.X][n.Loc.Y].Closed = true
return !p.Forced.Nodes[n.Loc.X][n.Loc.Y].Closed
}
This produces the following output:
Running setIll the first time
I'm running!
Running it again
And now we're done running
Notice that "I'm running!" only appears once in the output. Any idea why this may be?
It's not the switch tripping you up, it's how && works.
&& and || are short-circuiting operators: they don't execute what's on the right-hand side at all if the left-hand result is enough to determine what the answer will be. If your expression were a && f() and a were false it's not necessary to run f() to see that the end result will be false too. The way the Go spec puts this is "The right operand is evaluated conditionally."
This is common across a lot of languages. It's helpful when your first check has to pass for it to make sense to run the others. For example, say you want to check user permissions in a Web app, but only if a user is logged in at all (user != nil): user != nil && user.HasPermission(requiredPerm) does what you need.
If you want to set the check var the same way you're doing it now, but with setIll always called twice, you can assign the setIll results to variables outside of any && expression:
ck1, ck2 := p.setIll(n), p.setIll(s)
check = check && ck1 && ck2

Determine length of time keys are pressed

Can below script be modified so that the keys
"cl" fires "www.google.com" just if the "cl" keys
are both pressed for 500 milliseconds ?
Reason for this is that as part typing text sometimes the keys "cl" are pressed in rapid succession which then fires "www.google.com"
~l::
If (GetKeyState("c","p") && GetKeyState("l","p")) {
Send, {Backspace Down}{Backspace Up}{Backspace Down}{Backspace Up}
Run, "www.google.com"
}
Return
Using A_TickCount may be a good option.
~l::
duration := 0
If (GetKeyState("c","p") && GetKeyState("l","p"))
{
start := A_TickCount
While (GetKeyState("c") && GetKeyState("l"))
Sleep, 1
duration := A_TickCount - start
}
if (duration > 500)
Run, "www.google.com"
Return
This appears to do the trick :
~c::
~l::
If (GetKeyState("c","p") && GetKeyState("l","p")) {
Send, {Backspace Down}{Backspace Up}{Backspace Down}{Backspace Up}
sleep, 100
If (GetKeyState("c","p") && GetKeyState("l","p")) {
Run, "www.google.com"
}
Return
}
Return
Per this AutoHotKey forum post:
[T]he only way to program a key down for a specific duration is to use the down command and then a wait function with a (manually entered time) and then the up command[.]
So, you could solve this problem by putting a timer and then another if block inside your current if block, although it sounds like a bad idea.
A 500 millisecond delay could cause uncontrolled key repetition sothat we can't reliably delete the pressed keys anymore. So my suggestion is to find the repeat delay and only wait for so long minus ~150 milliseconds:
~c::
~l::
If (GetKeyState("c","p") && GetKeyState("l","p")) {
If (!GetKeyState("c","p") || !GetKeyState("l","p"))
Return
DllCall("SystemParametersInfo", UInt, 0x16, UInt, 0, UIntP, RepeatDelay, UInt, 0) ;get the key repeat delay
Sleep % (RepeatDelay+1)*250-150
If (GetKeyState("c","p") && GetKeyState("l","p")) {
SendInput, {c up}{l up}{BS}{BS}
Run, www.google.com
}
}
Return
SystemParametersInfo - SPI_GETKEYBOARDDELAY

C - passing an unknown command into execvp()

I'm writing a fake shell, where I create a child process and then call execvp(). In the normal shell, when I enter an unknown command such as 'hello' it returns 'hello: Command not found.' However, when I pass hello into execvp(), it doesn't return any error by default and just continues running the rest of my program like nothing happened. What's the easiest way to find out if nothing was actually run? here's my code:
if(fork() == 0)
{
execvp(cmd, args);
}
else
{
int status = 0;
int corpse = wait(&status);
printf(Child %d exited with a status of %d\n", corpse, status);
}
I know that if corpse < 0, then it's an unknown command, but there are other conditions in my code not listed where I don't want to wait (such as if & is entered at the end of a command). Any suggestions?
All of the exec methods can return -1 if there was an error (errno is set appropriately). You aren't checking the result of execvp so if it fails, the rest of your program will continue executing. You could have something like this to prevent the rest of your program from executing:
if (execvp(cmd, args) == -1)
exit(EXIT_FAILURE);
You also want to check the result of fork() for <0.
You have two independent concerns.
1) is the return value of execvp. It shouldn't return. If it does there is a problem. Here's what I get execvp'ing a bad command. You don't want to wait if execvp fails. Always check the return values.
int res = execvp(argv[1], argv);
printf ("res is %i %s\n", res, strerror(errno));
// => res is -1 No such file or directory
2) The other concern is background processes and such. That's the job of a shell and you're going to need to figure out when your program should wait immediately and when you want to save the pid from fork and wait on it later.

How to trace a program from its very beginning without running it as root

I'm writing a tool that calls through to DTrace to trace the program that the user specifies.
If my tool uses dtrace -c to run the program as a subprocess of DTrace, not only can I not pass any arguments to the program, but the program runs with all the privileges of DTrace—that is, as root (I'm on Mac OS X). This makes certain things that should work break, and obviously makes a great many things that shouldn't work possible.
The other solution I know of is to start the program myself, pause it by sending it SIGSTOP, pass its PID to dtrace -p, then continue it by sending it SIGCONT. The problem is that either the program runs for a few seconds without being traced while DTrace gathers the symbol information or, if I sleep for a few seconds before continuing the process, DTrace complains that objc<pid>:<class>:<method>:entry matches no probes.
Is there a way that I can run the program under the user's account, not as root, but still have DTrace able to trace it from the beginning?
Something like sudo dtruss -f sudo -u <original username> <command> has worked for me, but I felt bad about it afterwards.
I filed a Radar bug about it and had it closed as a duplicate of #5108629.
Well, this is a bit old, but why not :-)..
I don't think there is a way to do this simply from command line, but as suggested, a simple launcher application, such as the following, would do it. The manual attaching could of course also be replaced with a few calls to libdtrace.
int main(int argc, char *argv[]) {
pid_t pid = fork();
if(pid == 0) {
setuid(123);
seteuid(123);
ptrace(PT_TRACE_ME, 0, NULL, 0);
execl("/bin/ls", "/bin/ls", NULL);
} else if(pid > 0) {
int status;
wait(&status);
printf("Process %d started. Attach now, and click enter.\n", pid);
getchar();
ptrace(PT_CONTINUE, pid, (caddr_t) 1, 0);
}
return 0;
}
This script takes the name of the executable (for an app this is the info.plist's CFBundleExecutable) you want to monitor to DTrace as a parameter (you can then launch the target app after this script is running):
string gTarget; /* the name of the target executable */
dtrace:::BEGIN
{
gTarget = $$1; /* get the target execname from 1st DTrace parameter */
/*
* Note: DTrace's execname is limited to 15 characters so if $$1 has more
* than 15 characters the simple string comparison "($$1 == execname)"
* will fail. We work around this by copying the parameter passed in $$1
* to gTarget and truncating that to 15 characters.
*/
gTarget[15] = 0; /* truncate to 15 bytes */
gTargetPID = -1; /* invalidate target pid */
}
/*
* capture target launch (success)
*/
proc:::exec-success
/
gTarget == execname
/
{
gTargetPID = pid;
}
/*
* detect when our target exits
*/
syscall::*exit:entry
/
pid == gTargetPID
/
{
gTargetPID = -1; /* invalidate target pid */
}
/*
* capture open arguments
*/
syscall::open*:entry
/
((pid == gTargetPID) || progenyof(gTargetPID))
/
{
self->arg0 = arg0;
self->arg1 = arg1;
}
/*
* track opens
*/
syscall::open*:return
/
((pid == gTargetPID) || progenyof(gTargetPID))
/
{
this->op_kind = ((self->arg1 & O_ACCMODE) == O_RDONLY) ? "READ" : "WRITE";
this->path0 = self->arg0 ? copyinstr(self->arg0) : "<nil>";
printf("open for %s: <%s> #%d",
this->op_kind,
this->path0,
arg0);
}
If the other answer doesn't work for you, can you run the program in gdb, break in main (or even earlier), get the pid, and start the script? I've tried that in the past and it seemed to work.
Create a launcher program that will wait for a signal of some sort (not necessarily a literal signal, just an indication that it's ready), then exec() your target. Now dtrace -p the launcher program, and once dtrace is up, let the launcher go.
dtruss has the -n option where you can specify name of process you want to trace, without starting it (Credit to latter part of #kenorb's answer at https://stackoverflow.com/a/11706251/970301). So something like the following should do it:
sudo dtruss -n "$program"
$program
There exists a tool darwin-debug that ships in Apple's CLT LLDB.framework which will spawn your program and pause it before it does anything. You then read the pid out of the unix socket you pass as an argument, and after attaching the debugger/dtrace you continue the process.
darwin-debug will exec itself into a child process <PROGRAM> that is
halted for debugging. It does this by using posix_spawn() along with
darwin specific posix_spawn flags that allows exec only (no fork), and
stop at the program entry point. Any program arguments <PROGRAM-ARG> are
passed on to the exec as the arguments for the new process. The current
environment will be passed to the new process unless the "--no-env"
option is used. A unix socket must be supplied using the
--unix-socket=<SOCKET> option so the calling program can handshake with
this process and get its process id.
See my answer on related question "How can get dtrace to run the traced command with non-root priviledges?" [sic].
Essentially, you can start a (non-root) background process which waits 1sec for DTrace to start up (sorry for race condition), and snoops the PID of that process.
sudo true && \
(sleep 1; cat /etc/hosts) &; \
sudo dtrace -n 'syscall:::entry /pid == $1/ {#[probefunc] = count();}' $! \
&& kill $!
Full explanation in linked answer.

Resources