OneLiner conditonal pipe in bash - bash

Problem
I want to find a simple, single line way to pipe a string depending on a certain condition
Attempt
The above code was my attempt at making a pipe conditional depending on a variable called textfolding.
textfolding="ON"
echo "some text blah balh test foo" if [[ "$textfolding" == "ON" ]]; then | fold -s -w "$fold_width" | sed -e "s|^|\t|g"; fi
This obviously did not work.
Final
How could I achieve this on the same one line?

You can't make the pipe itself conditional, but you can include an if block as an element of the pipeline:
echo "some text blah balh test foo" | if [[ "$textfolding" == "ON" ]]; then fold -s -w "$fold_width" | sed -e "s|^|\t|g"; else cat; fi
Here's a more readable version:
echo "some text blah balh test foo" |
if [[ "$textfolding" == "ON" ]]; then
fold -s -w "$fold_width" | sed -e "s|^|\t|g"
else
cat
fi
Note that since the if block is part of the pipeline, you need to include something like an else cat clause (as I did above) so that whether the if condition is true or not, something will pass the piped data through. Without the cat, it'd just get dropped on the metaphorical floor.

How about conditional execution?
textfolding="ON"
string="some text blah balh test foo"
[[ $textfolding == "ON" ]] && echo $string | fold -s -w $fold_width | sed -e "s|^|\t|g" || echo $string

Related

How to cut variables which are beteween quotes from a string

I had problem with cut variables from string in " quotes. I have some scripts to write for my sys classes, I had a problem with a script in which I had to read input from the user in the form of (a="var1", b="var2")
I tried the code below
#!/bin/bash
read input
a=$($input | cut -d '"' -f3)
echo $a
it returns me a error "not found a command" on line 3 I tried to double brackets like
a=$(($input | cut -d '"' -f3)
but it's still wrong.
In a comment the OP gave a working answer (should post it as an answer):
#!/bin/bash
read input
a=$(echo $input | cut -d '"' -f2)
b=$(echo $input | cut -d '"' -f4)
echo sum: $(( a + b))
echo difference: $(( a - b))
This will work for user input that is exactly like a="8", b="5".
Never trust input.
You might want to add the check
if [[ ${input} =~ ^[a-z]+=\"[0-9]+\",\ [a-z]+=\"[0-9]+\"$ ]]; then
echo "Use your code"
else
echo "Incorrect input"
fi
And when you add a check, you might want to execute the input (after replacing the comma with a semicolon).
input='testa="8", testb="5"'
if [[ ${input} =~ ^[a-z]+=\"[0-9]+\",\ [a-z]+=\"[0-9]+\"$ ]];
then
eval $(tr "," ";" <<< ${input})
set | grep -E "^test[ab]="
else
echo no
fi
EDIT:
#PesaThe commented correctly about BASH_REMATCH:
When you use bash and a test on the input you can use
if [[ ${input} =~ ^[a-z]+=\"([0-9]+)\",\ [a-z]+=\"([0-9])+\"$ ]];
then
a="${BASH_REMATCH[1]}"
b="${BASH_REMATCH[2]}"
fi
To extract the digit 1 from a string "var1" you would use a Bash substring replacement most likely:
$ s="var1"
$ echo "${s//[^0-9]/}"
1
Or,
$ a="${s//[^0-9]/}"
$ echo "$a"
1
This works by replacing any non digits in a string with nothing. Which works in your example with a single number field in the string but may not be what you need if you have multiple number fields:
$ s2="1 and a 2 and 3"
$ echo "${s2//[^0-9]/}"
123
In this case, you would use sed or grep awk or a Bash regex to capture the individual number fields and keep them distinct:
$ echo "$s2" | grep -o -E '[[:digit:]]+'
1
2
3

Two "if" conditions in the same time

I am writing a script to bring me data from other nodes via ssh in a multi selection choice menu, and i want to display a message according to this data.
if [[ "$option" == "1" ]]
then
ssh skyusr#<IP> "export JAVA_HOME=/opt/mesosphere && /var/lib/mesos/slave/slaves/*/frameworks/*/executors/*/runs/latest/apache-cassandra-3.0.10/bin/nodetool -p 7199 status" | sed -n '6,10p' | awk '{print $1,$2}' | grep DN > $file_name
if [ -s $file_name ]
then
echo "All Cassandra Nodes are UP !"
else cat "$file_name"
fi
fi
When i execute the script, i see it does not see the second if condition to display the message .
What is the correct syntax ?
There is, as far as I can see, nothing wrong with the syntax. You might want to do something about spacing etc. to enhance readability, but that is it.
I assumed, that file_name is set somewhere before this part, as is option.
If things do not work as you expect them to work, you can add some statements for debugging purposes, which you must remove later on. For example, in this case, I would like to see the output of the ssh and add some echo's to see the flow-control:
if [[ "$option" == "1" ]] ; then
ssh skyusr#<IP> "export JAVA_HOME=/opt/mesosphere && /var/lib/mesos/slave/slaves/*/frameworks/*/executors/*/runs/latest/apache-cassandra-3.0.10/bin/nodetool -p 7199 status" > tempfile
cat tempfile |
sed -n '6,10p' |
awk '{print $1,$2}' |
grep DN > "$file_name"
if [ -s "$file_name" ] ; then
echo "All Cassandra Nodes are UP !"
else
echo "$file_name is not empty"
cat "$file_name"
fi
fi
You can use the tempfile to verify that your sed, awk, grep combination acts correctly.

bash: sed: unexpected behavior: displays everything

I wrote what I thought was a quick script I could run on a bunch of machines. Instead it print what looks like might be directory contents in a recursive search:
version=$(mysql Varnish -B --skip-column-names -e "SELECT value FROM sys_param WHERE param='PatchLevel'" | sed -n 's/^.*\([0-9]\.[0-9]*\).*$/\1/p')
if [[ $(echo "if($version == 6.10) { print 1; } else { print 0; }" | bc) -eq 1 ]]; then
status=$(dpkg-query -l | awk '{print $2}' | grep 'sg-status-polling');
cons=$(dpkg-query -l | awk '{print $2}' | grep 'sg-consolidated-poller');
if [[ "$status" != "" && "$cons" != "" ]]; then
echo "about to change /var/www/Varnish/lib/Extra/SG/ObjectPoller2.pm"; echo;
cp /var/www/Varnish/lib/Extra/SG/ObjectPoller2.pm /var/www/Varnish/lib/Extra/SG/ObjectPoller2.pm.bkup;
sed -ir '184s!\x91\x93!\x91\x27--timeout=35\x27\x93!' /var/www/Varnish/lib/Extra/SG/ObjectPoller2.pm;
sed -n 183,185p /var/www/Varnish/lib/Extra/SG/ObjectPoller2.pm; echo;
else
echo "packages not found. Assumed to be not applicable";
fi
else
echo "This is 4.$version, skipping";
fi
The script is supposed to make sure Varnish is version 4.6.10 and has 2 custom .deb packages installed (not through apt-get). then makes a backup and edits a single line in a perl module from [] to ['--timeout=35']
it looks like its tripping up on the sed replace one liner.
There are two major problems (minor ones addressed in comments). The first is that you use the decimal code for [] instead of the hexa, so you should use \x5b\x5d instead of \x91\x93. The second problem is that if you do use the proper codes, sed will still interpret those syntactically as []. So you can't escape escaping. Here's what you should call:
sed -ri'.bkup' '184s!\[\]![\x27--timeout=35\x27]!' /var/www/Varnish/lib/Extra/SG/ObjectPoller2.pm
And this will create the backup for you (but you should double check).

Bash string variable won't pass value

If the last pipe is removed, it seems the value will pass and things will work until the connection is no longer active. Then the value then goes empty or null with a double quote still there. The sed command can strip that but the pipe won't let the value afterwards be passed. I'm stuck.
iwgetid wlan0 | grep 'ESSID:' | cut -c 18-24 | wtf=$(echo "$1"
[[ -z "$1" ]] && echo -e "Wi-Fi Not Connected!" || echo -e "Connected"
Anything on the right-hand side of a pipeline is run in a subshell, meaning that assignments done there aren't visible anywhere else in your shell.
Also, where you get $1 from is unclear here -- the values from wtf aren't getting into the positional arguments by anything you're doing. Fixing that:
wtf=$(iwgetid wlan0 | grep 'ESSID:' | cut -c 18-24 | sed -e 's/^"//' -e 's/"$//')
[[ -z "$wtf" ]] && echo -e "Wi-Fi Not Connected!" || echo -e "Connected"
[[ ! -z "$wtf" ]] && echo -e "Connected" || echo -e "Wi-Fi Not Connected!"
...that said -- this is really awful code. Readers, please don't consider places where I'm quoting from the OP as condoning same. :)

if condition with multiple grep commands not working

The following bash snippet gives "conditional binary operator expected"
countries=$1
while read -r line; do
if [[ echo "$line" | grep BUSINESS | grep -E "$countries" ]]; then
echo $line >> "$Business_Accounts"
fi
done
What's going wrong?
Just change your if statement like below,
if [[ $(echo "$line" | grep BUSINESS | grep -E "$countries") ]]; then
OR
You could do like the above in a single grep command like in the below example because grep or awk or sed processes the input line by line.
$ contries="foo"
$ echo 'foo BUSINESS bar
bar' | grep -P "^(?=.*BUSINESS).*$con"
foo BUSINESS bar
$ Business_account=$(echo 'foo BUSINESS bar
bar' | grep -P "^(?=.*BUSINESS).*$con")
$ echo "$Business_account"
foo BUSINESS bar
In a single line, it would be like,
Business_account=$(grep -P "^(?=.*BUSINESS).*$contries" file)

Resources