Creating flag for print the output of shell script - shell

I am creating a shell script. Now, I want to create a flag to print the output of script on the screen if flag is ON otherwise script will not print the output if flag is OFF
Thanks

This might work for you:
#!/bin/bash
# assuming your first argument is the printing flag
[[ "${1}" = "ON" ]] && OUTPUT="/dev/stdout" || OUTPUT="/dev/null"
# from now on:
echo "Something" > $OUTPUT
# will work as expected...

test.sh code below:
#!/bin/sh
while IFS= read -r line
do
cat "$line"
done < $1
Test it:
$ ls
myflags testfile0 testfile1 testfile2 test.py test.sh
$ cat myflags
testfile0
testfile1
test.py
$ cat testfile0
some test
$ sh test.sh myflags
some test
#!/usr/bin/python
import sys
if sys.version_info[0] == 2:
sys.stdout.write("ls -l")
$

Related

sed command find and replace in file and overwrite file , how to initialize file has current file/script

I wanted to increment the current decimal variable,
so I made the following code
#! /bin/bash
k=1.3
file=/home/script.sh
next_k=$(echo "$k + 0.1" | bc -l)
sed -i "s/$k/$next_k/g" "$file"
echo $k
As you can see here I have to specify the file in line 3 , is there a workaround to just tell it to edit and replace in the current file. Instead of me pointing it to the file. Thank you.
I think you're asking how to reference the own script name, which $0 holds, e.g.
#! /bin/bash
k=1.3
next_k=$(echo "$k + 0.1" | bc -l)
sed -i "s/$k/$next_k/g" "$0"
echo $k
You can read more on Positional Parameters here, specifically this bit:
($0) Expands to the name of the shell or shell script. This is set at shell initialization. If Bash is invoked with a file of commands (see Shell Scripts), $0 is set to the name of that file. If Bash is started with the -c option (see Invoking Bash), then $0 is set to the first argument after the string to be executed, if one is present. Otherwise, it is set to the filename used to invoke Bash, as given by argument zero.
e.g.
$ cat test.sh
#! /bin/bash
k=1.3
next_k=$(echo "$k + 0.1" | bc -l)
sed -i "s/$k/$next_k/g" $0
echo $k
$ ./test.sh; ./test.sh ; ./test.sh
1.3
1.4
1.5
$ cat test.sh
#! /bin/bash
k=1.6
next_k=$(echo "$k + 0.1" | bc -l)
sed -i "s/$k/$next_k/g" $0
echo $k

Ignoring all but the (multi-line) results of the last query sent to a program

I have an executable that accepts queries from stdin and responds to them, reading until EOF. Additionally I have an input file and a special command, let's call those EXEC, FILE and CMD respectively.
What I need to do is:
Pass FILE to EXEC as input.
Disregard all the output corresponding to commands read from FILE (/dev/null/).
Pass CMD as the last command.
Fetch output for the last command and save it in a variable.
EXEC's output can be multiline for each query.
I know how to pass FILE + CMD into the EXEC:
echo ${CMD} | cat ${FILE} - | ${EXEC}
but I have no idea how to fetch only output resulting from CMD.
Is there a magical one-liner that does this?
After looking around I've found the following partial solution:
mkfifo mypipe
(tail -f mypipe) | ${EXEC} &
cat ${FILE} | while read line; do
echo ${line} > mypipe
done
echo ${CMD} > mypipe
This allows me to redirect my input, but now the output gets printed to screen. I want to ignore all the output produced by EXEC in the while loop and get only what it prints for the last line.
I tried what first came into my mind, which is:
(tail -f mypipe) | ${EXEC} > somefile &
But it didn't work, the file was empty.
This is race-prone -- I'd suggest putting in a delay after the kill, or using an explicit sigil to determine when it's been received. That said:
#!/usr/bin/env bash
# route FD 4 to your output routine
exec 4> >(
output=; trap 'output=1' USR1
while IFS= read -r line; do
[[ $output ]] && printf '%s\n' "$line"
done
); out_pid=$!
# Capture the PID for the process substitution above; note that this requires a very
# new version of bash (4.4?)
[[ $out_pid ]] || { echo "ERROR: Your bash version is too old" >&2; exit 1; }
# Run your program in another process substitution, and close the parent's handle on FD 4
exec 3> >("$EXEC" >&4) 4>&-
# cat your file to FD 3...
cat "$file" >&3
# UGLY HACK: Wait to let your program finish flushing output from those commands
sleep 0.1
# notify the subshell writing output to disk that the ignored input is done...
kill -USR1 "$out_pid"
# UGLY HACK: Wait to let the subprocess actually receive the signal and set output=1
sleep 0.1
# ...and then write the command for which you actually want content logged.
echo "command" >&3
In validating this answer, I'm doing the following:
EXEC=stub_function
stub_function() {
local count line
count=0
while IFS= read -r line; do
(( ++count ))
printf '%s: %s\n' "$count" "$line"
done
}
cat >file <<EOF
do-not-log-my-output-1
do-not-log-my-output-2
do-not-log-my-output-3
EOF
file=file
export -f stub_function
export file EXEC
Output is only:
4: command
You could pipe it into a sed:
var=$(YOUR COMMAND | sed '$!d')
This will put only the last line into the variable
I think, that your proram EXEC does something special (open connection or remember state). When that is not the case, you can use
${EXEC} < ${FILE} > /dev/null
myvar=$(echo ${CMD} | ${EXEC})
Or with normal commands:
# Do not use (printf "==%s==\n" 1 2 3 ; printf "oo%soo\n" 4 5 6) | cat
printf "==%s==\n" 1 2 3 | cat > /dev/null
myvar=$(printf "oo%soo\n" 4 5 6 | cat)
When you need to give all input to one process, perhaps you can think of a marker that you can filter on:
(printf "==%s==\n" 1 2 3 ; printf "%s\n" "marker"; printf "oo%soo\n" 4 5 6) | cat | sed '1,/marker/ d'
You should examine your EXEC what could be used. When it is running SQL, you might use something like
(cat ${FILE}; echo 'select "DamonMarker" from dual;' ; echo ${CMD} ) |
${EXEC} | sed '1,/DamonMarker/ d'
and write this in a var with
myvar=$( (cat ${FILE}; echo 'select "DamonMarker" from dual;' ; echo ${CMD} ) |
${EXEC} | sed '1,/DamonMarker/ d' )

Exporting dependant variable failed in shell script

I have three shell script files, one global variable named "VER" and its value is "2017.4"
1. variable.sh
2. function.sh
3. main.sh
variable.sh
var1=/home
var2=/home/${VER}_version
function.sh
Contain a function named export_function which takes one variable as argument, perform grep operation to find that variable from variable.sh file and export the grep output
export_function () {
var=`grep "$1=" variable.sh | sed -e "s/"$1="//g"`
export $1=$var
}
main.sh
source function.sh
export_function var2
echo "$var2"
When I run the main.sh, get output: /home/${VER}_version instead of /home/2017.4_version
Note: echo $VER in main.sh and function.sh shows value 2017.4
Constrains:
variable.sh is a read-only file
source variable.sh is not allowed
I've rewritten your scripts like that, and it works:
[sahaquiel#sahaquiel-PC ~]$ cat variable.sh
#!/bin/bash
var1=/home
var2="/home/${VAR22}_version"
[sahaquiel#sahaquiel-PC ~]$ cat function.sh
#!/bin/bash
export_function () {
source variable.sh
var=$(echo "var2=${var2}" | grep "$1=" | sed -e "s/"$1="//g")
export $1=$var
}
[sahaquiel#sahaquiel-PC ~]$ cat main.sh
#!/bin/bash
source function.sh
export_function var2
echo "$var2"
[sahaquiel#sahaquiel-PC ~]$ bash main.sh
/home/2017.4_version
[sahaquiel#sahaquiel-PC ~]$ echo $VAR22
2017.4

STDIN Pipe file into for loop

I was wondering is there a way that i can enter
./myscript.sh FILENAME
and the file will link into
for a in $(cat FILENAME) ; do
done
Calling your script with:
./myscript.sh babynames
You can process each line of you file with read:
while read -r line; do
echo "$line"
done < "$1"
$ cat > myscript.sh # create myscript.sh
for i in "$(cat $1)" ; do echo "$i" ; done # in the end CTRL-d
$ cat > babynames # create babynames
primo
secundo # in the end CTRL-d
$ bash myscript.sh babynames # execute the script with babynames as parameter
primo
secundo

How can bash read from piped input or else from the command line argument

I would like to read some data either from pipe or from the command line arguments (say $1), whichever is provided (priority has pipe).
This fragment tells me if the pipe was open or not but I don't know what to put inside in order not to block the script (test.sh) (using read or cat)
if [ -t 0 ]
then
echo nopipe
DATA=$1
else
echo pipe
# what here?
# read from pipe into $DATA
fi
echo $DATA
Executing the test.sh script above I should get the following output:
$ echo 1234 | test.sh
1234
$ test.sh 123
123
$ echo 1234 | test.sh 123
1234
You can read all of stdin into a variable with:
data=$(cat)
Note that what you're describing is non-canonical behavior. Good Unix citizens will:
Read from a filename if supplied as an argument (regardless of whether stdin is a tty)
Read from stdin if no file is supplied
This is what you see in sed, grep, cat, awk, wc and nl to name only a few.
Anyways, here's your example with the requested feature demonstrated:
$ cat script
#!/bin/bash
if [ -t 0 ]
then
echo nopipe
data=$1
else
echo pipe
data=$(cat)
fi
echo "$data"
$ ./script 1234
nopipe
1234
$ echo 1234 | ./script
pipe
1234

Resources