Hacking exercise / How can I pass a new terminal command to an existing terminal command? - terminal

If we got this command line:
python file.py --gsgds dsgsdg --dg dgdg --dg 'gdgd'
And now, let's say we want to break this command and run another command while it is running, something like that:
python file.py --gsgds dsgsdg --dg dgdg --dg '`sleep 10`'
When I try to add a sleep 10 between the two quotes, it doesn't work. Please keep in mind that I must break the command between the two quotes. ('[inject here]')
Any ideas?

Let's take for example, we have bash shell running in the terminal. There are several characters which have special meaning in the bash shell. You can read more in the bash manual.
Let's take for example, ; in bash.
You can easily run sleep 10 after your python command using ;. Here's one way:
python file.py --gsgds dsgsdg --dg dgdg --dg ''; sleep 1; echo 'Done'
where you pass '; sleep 1; echo 'Done in the third arg.
Some shells add restriction on what characters can/ cannot be used so it's up to you to try out what works.

Related

Bash script not ending because of the background processes

I have a bash script as given below: It runs the python script with different arguments, each one as a background process (note that I have used '&')
#!/bin/bash
declare -a arr=("arg1" "arg2" "arg3")
for i in "${arr[#]}"
do
echo "$i"
python3 test.py $i &
echo "hi"
done
exit
The test.py file is as shown below:
import sys
print('Argument List:', str(sys.argv))
I tried to run the bash script with the command ./bash_script_test.sh.
Output is also right, but the script just doesnt end running. Plus the python code's output starts in a new command line. Refer below for the output.
arg1
hi
arg2
hi
arg3
hi
[root#csit-openstack1 risav]# Argument List: ['test.py', 'arg2']
Argument List: ['test.py', 'arg3']
Argument List: ['test.py', 'arg1']
Why is a new command line coming up and why is the shell script not exiting? Is it because of the use of & ? If yes, can somebody explain?
Take a cup of red color and a cup of green color and pour them into the same bucket. The result is a brown mess. The same happens with your terminal.
You have two processes, the foreground and the background process. Both write at the same time to the same terminal. The result is a mess. Background processes should write to log files instead.
Replace the line
python3 test.py $i &
with
python3 test.py $i > $i.log &
to give each background process its own log file.
If you want to merge the different sources, you have to use a tool like Syslog.
BTW: the script is ending. The last thing it does in the loop is printing "hi". And your output shows three times a "hi".

How can I start a subscript within a perpetually running bash script after a specific string has been printed in the terminal output?

Specifics:
I'm trying to build a bash script which needs to do a couple of things.
Firstly, it needs to run a third party script that I cannot manipulate. This script will build a project and then start a node server which outputs data to the terminal continually. This process needs to continue indefinitely so I can't have any exit codes.
Secondly, I need to wait for a specific line of output from the first script, namely 'Started your app.'.
Once that line has been output to the terminal, I need to launch a separate set of commands, either from another subscript or from an if or while block, which will change a few lines of code in the project that was built by the first script to resolve some dependencies for a later step.
So, how can I capture the output of the first subscript and use that to run another set of commands when a particular line is output to the terminal, all while allowing the first script to run in the terminal, and without using timers and without creating a huge file from the output of subscript1 as it will run indefinitely?
Pseudo-code:
#!/usr/bin/env bash
# This script needs to stay running & will output to the terminal (at some point)
# a string that we need to wait/watch for to launch subscript2
sh subscript1
# This can't run until subscript1 has output a particular string to the terminal
# This could be another script, or an if or while block
sh subscript2
I have been beating my head against my desk for hours trying to get this to work. Any help would be appreciated!
I think this is a bad idea — much better to have subscript1 changed to be automation-friendly — but in theory you can write:
sh subscript1 \
| {
while IFS= read -r line ; do
printf '%s\n' "$line"
if [[ "$line" = 'Started your app.' ]] ; then
sh subscript2 &
break
fi
done
cat
}

Storing execution time of a command in a variable

I am trying to write a task-runner for command line. No rationale. Just wanted to do it. Basically it just runs a command, stores the output in a file (instead of stdout) and meanwhile prints a progress indicator of sorts on stdout and when its all done, prints Completed ($TIME_HERE).
Here's the code:
#!/bin/bash
task() {
TIMEFORMAT="%E"
COMMAND=$1
printf "\033[0;33m${2:-$COMMAND}\033[0m\n"
while true
do
for i in 1 2 3 4 5
do
printf '.'
sleep 0.5
done
printf "\b\b\b\b\b \b\b\b\b\b"
sleep 0.5
done &
WHILE=$!
EXECTIME=$({ TIMEFORMAT='%E';time $COMMAND >log; } 2>&1)
kill -9 $WHILE
echo $EXECTIME
#printf "\rCompleted (${EXECTIME}s)\n"
}
There are some unnecessarily fancy bits in there I admit. But I went through tons of StackOverflow questions to do different kinds of fancy stuff just to try it out. If it were to be applied anywhere, a lot of fat could be cut off. But it's not.
It is to be called like:
task "ping google.com -c 4" "Pinging google.com 4 times"
What it'll do is print Pinging google.com 4 times in yellow color, then on the next line, print a period. Then print another period every .5 seconds. After five periods, start from the beginning of the same line and repeat this until the command is complete. Then it's supposed to print Complete ($TIME_HERE) with (obviously) the time it took to execute the command in place of $TIME_HERE. (I've commented that part out, the current version would just print the time).
The Issue
The issue is that that instead of the execution time, something very weird gets printed. It's probably something stupid I'm doing. But I don't know where that problem originates from. Here's the output.
$ sh taskrunner.sh
Pinging google.com 4 times
..0.00user 0.00system 0:03.51elapsed 0%CPU (0avgtext+0avgdata 996maxresident)k 0inputs+16outputs (0major+338minor)pagefaults 0swaps
Running COMMAND='ping google.com -c 4';EXECTIME=$({ TIMEFORMAT='%E';time $COMMAND >log; } 2>&1);echo $EXECTIME in a terminal works as expected, i.e. prints out the time (3.559s in my case.)
I have checked and /bin/sh is a symlink to dash. (However that shouldn't be a problem because my script runs in /bin/bash as per the shebang on the top.)
I'm looking to learn while solving this issue so a solution with explanation will be cool. T. Hanks. :)
When you invoke a script with:
sh scriptname
the script is passed to sh (dash in your case), which will ignore the shebang line. (In a shell script, a shebang is a comment, since it starts with a #. That's not a coincidence.)
Shebang lines are only interpreted for commands started as commands, since they are interpreted by the system's command launcher, not by the shell.
By the way, your invocation of time does not correctly separate the output of the time builtin from any output the timed command might sent to stderr. I think you'd be better with:
EXECTIME=$({ TIMEFORMAT=%E; time $COMMAND >log.out 2>log.err; } 2>&1)
but that isn't sufficient. You will continue to run into the standard problems with trying to put commands into string variables, which is that it only works with very simple commands. See the Bash FAQ. Or look at some of these answers:
How to escape a variable in bash when passing to command line argument
bash quotes in variable treated different when expanded to command
Preserve argument splitting when storing command with whitespaces in variable
find command fusses on -exec arg
Using an environment variable to pass arguments to a command
(Or probably hundreds of other similar answers.)

How can I monitor a bash script?

I am running a bash script that takes hours. I was wondering if there is way to monitor what is it doing? like what part of the script is currently running, how long did it take to run the whole script, if it crashes at what line of the script stopped working, etc. I just want to receive feedback from the script. Thanks!!!
from man page for bash,
set -x
After expanding each simple command, for command, case command, select command, or arithmetic for command, display the expanded value of PS4, followed by the command and its expanded arguments or associated word list.
add these to the start of your script,
export PS4='+{${BASH_SOURCE}:$LINENO} '
set -x
Example,
#!/bin/bash
export PS4='+{${BASH_SOURCE}:$LINENO} '
set -x
echo Hello World
Result,
+{helloworld.sh:6} echo Hello World
Hello World
Make a status or log file. For example add this inside your script:
echo $(date) - Ok >> script.log
Or for a real monitoring you can use strace on linux for see system call, example:
$ while true ; do sleep 5 ; done &
[1] 27190
$ strace -p 27190

Input to Expect Script

in my test file, I had this line hello$LG. So, if I do
`cat /test`
It will show in my bash shell - hello$LG
But when I try to do this in my expect script,
$> expect test.sh `cat /test`
It gives me this {hello$LG} . I don't know why it is getting {}. Anyone knows how to fix this?
Expect is based upon TCL, you should use square brackets to execute code. When trying to execute a shell command you should use either exec or open or spawn.
I am not sure what the test.sh does, but
expect [exec test.sh 'cat /test']
might just do the trick.
There's more on running other programs from Tcl here:
http://www.tcl.tk/man/tcl/tutorial/Tcl26.html

Resources