Converting multiple lines of bash in to a single line - bash

Is there any short and easy way to convert multiple lines of script in to a single line to be parsed in a eval command?
ie
getent group | cut -f3 -d":" | sort -n | uniq -c |\
while read x ; do
[ -z "${x}" ] && break
set - $x ; if [ $1 -gt 1 ]; then
grps=`getent group | nawk -F: '($3 == n) { print $1 }' n=$2 | xargs` ; echo "Duplicate GID ($2): ${grps}" ; fi done

one_line=`cat your_script_file | sed ":a s/[\]$//; N; s/[\]$//; s/\n/ /; t a ;"`
echo $one_line

Related

How to break pipe if stdin is empty?

I want to break the whole pipe if the stdin is empty. I try to combined xargs -r and tee, which means not print and write if stdin is empty, but it failed
...| upstream commands | xargs -r tee output.txt | downstream commands | ...
Any feedback appreciated.
There is no way you can actually terminate a bash pipe conditionally. All commands in a pipeline are started simultaneously. There is however a tool available that would assist you with creating a conditional pipeline. In moreutils you can find the tool ifne which executes a command if and only if the input /dev/stdin is not empty. So you could write something like:
$ command1 | ifne command2 | ifne command3 | ifne command4
Here all commands ifne and command1 are started simultaniously. Only if ifne receives input via /dev/stdin, it will start its respective commandx
Pipe'll break if command failed. You can add grep in between to achieve this. An example:
$ echo ok | awk '{print $0,"1"}' | awk '{print $0,"2"}' | awk '{print $0,"3"}'
ok 1 2 3
Now add grep:
$ echo ok | grep -Ei '^.+$' | awk '{print $0,"1"}' | awk '{print $0,"2"}' | awk '{print $0,"3"}'
ok 1 2 3
And test empty echo:
$ echo | awk '{print $0,"1"}' | awk '{print $0,"2"}' | awk '{print $0,"3"}'
1 2 3
$ echo | grep -Ei '^.+$' | awk '{print $0,"1"}' | awk '{print $0,"2"}' | awk '{print $0,"3"}'
Looks like this works but it doesn't, interesting indeed, well then obvy pipes don't fit here, try this approach:
#!/bin/bash
set -x
fun(){
data=$(echo "$1"); [[ $data ]] && data=$(awk '{print $0,1}' <<< "$data") || return 1; [[ $data ]] && data=$(awk '{print $0,2}' <<< "$data") || return 1; [[ $data ]] && data=$(awk '{print $0,3}' <<< "$data") || return 1; echo "$data"
}
fun ok
fun
Testing:
$ ./test
+ fun ok
++ echo ok
+ data=ok
+ [[ -n ok ]]
++ awk '{print $0,1}'
+ data='ok 1'
+ [[ -n ok 1 ]]
++ awk '{print $0,2}'
+ data='ok 1 2'
+ [[ -n ok 1 2 ]]
++ awk '{print $0,3}'
+ data='ok 1 2 3'
+ echo 'ok 1 2 3'
ok 1 2 3
+ fun
++ echo ''
+ data=
+ [[ -n '' ]]
+ return 1
More readable variant:
#!/bin/bash
set -x
fun(){
data=$(echo "$1")
[[ $data ]] && data=$(awk '{print $0,1}' <<< "$data") || return 1
[[ $data ]] && data=$(awk '{print $0,2}' <<< "$data") || return 1
[[ $data ]] && data=$(awk '{print $0,3}' <<< "$data") || return 1
echo "$data"
}
fun ok
fun

How to fix "syntax error near unexpected token `done' " in a nested loop in bash?

I am writing a script that will loop through columns to find an instance of a word.
I decided I do it through nested loops and after executing my code, I get this error:
./gallupscript.sh: line 115: syntax error near unexpected token done'
./gallupscript.sh: line 115:done'
Here is the area where my code fails:
token=2 #token is the column number
starter=0
s1="First" ; s2="Second" ; s3="Third" ; s4="Fourth" ; s5="Fifth"
s=s ; a=1
while [ $token -le 6 ]
do
cat gallup.csv | cut -d',' -f"$token" | grep -n $strength1 | cut -d':' -f1 > str1
if [ -s str1 ]
then
for i in $(cat str1)
do
if [[ $i -ne $number && $starter -eq 0 ]]
then
save=$(cat gallup.csv | head -$i | tail +$i | cut -d',' -f1)
s=s ; s+=$a ; starter=1
printf "-- $strength1 --"
printf "${!s} Strength: $save"
elif [[ $i -ne $number && $starter -ne 0 ]]
then
save=$(cat gallup.csv | head -$i | tail +$i | cut -d',' -f1)
printf ", $save"
fi
done
starter=0
a=$((a+1))
token=$((token+1))
echo #new line
done
This code is expected to output the names (in first columns) where the word is matched with the one I am searching for.
You are not closing your if statement, it doesn't have to do with for.
Use the following code instead:
token=2 #token is the column number
starter=0
s1="First" ; s2="Second" ; s3="Third" ; s4="Fourth" ; s5="Fifth"
s=s ; a=1
while [ $token -le 6 ]
do
cat gallup.csv | cut -d',' -f"$token" | grep -n $strength1 | cut -d':' -f1 > str1
if [ -s str1 ]
then
for i in $(cat str1)
do
if [[ $i -ne $number && $starter -eq 0 ]]
then
save=$(cat gallup.csv | head -$i | tail +$i | cut -d',' -f1)
s=s ; s+=$a ; starter=1
printf "-- $strength1 --"
printf "${!s} Strength: $save"
elif [[ $i -ne $number && $starter -ne 0 ]]
then
save=$(cat gallup.csv | head -$i | tail +$i | cut -d',' -f1)
printf ", $save"
fi
done
fi # <------------ add this line
starter=0
a=$((a+1))
token=$((token+1))
echo #new line
done

String comparison from nested for returns always false

The main issue is that i try to parse ls to do a mock "Compare directories" but when i do so since i use nested fors i cant properly compare the results from it since the comparison of two filenames/strings even if they are the same it always returns false
I tried erasing the white characters but no results.
var1=$(ls -l $1 | grep -v ^d | tail -n +2 | tr -s " "| cut -d " " -f 9)
var2=$(ls -l $2 | grep -v ^d | tail -n +2 | tr -s " "| cut -d " " -f 9)
for i in $var1 ; do
i=$(printf "$i" | tr -d '[:space:]')
flag=0
var3=$(ls -l $1 | grep -v ^d | tail -n +2 | tr -s " " | grep $i | cut -d " " -f 5)
for j in $var2 ; do
j=$(printf $j | tr -d '[:space:]')
var4=$(ls -l $2 | grep -v ^d | tail -n +2 | tr -s " " | grep $j | cut -d " " -f 5)
if [ "$i" == "$j" ] ; then
if [ "$var3" != "$var4" ] ; then
flag=1
fi
else
flag=1
fi
done
if [ $flag -eq 1 ] ; then
printf "$i file does not exist on the $2 catalog\n"
printf "It 's size is :$var3 \n"
let Sum=$Sum+$var3
fi
done
This is not a string comparison problem, it's a logic problem.
I wrote you a MCVE that demonstrates the same problem with less code and fewer dependencies:
flag=0
target="hello"
for candidate in "hello" "world"
do
if [ "$target" != "$candidate" ]
then
flag=1
fi
done
if [ "$flag" -eq 1 ]
then
echo "The string was not found"
fi
This prints The string was not found every time, just like your script, even though it's clearly there.
The problem here is that the script requires that ALL files match. It should only require that ANY file matches. The easiest way to fix this is to:
Set flag=1 when a MATCH is found (not a mismatch)
Make flag=1 signify that a match was found (rather than no match was found)
Here's the version which correctly finds the string:
flag=0
target="hello"
for candidate in "hello" "world"
do
if [ "$target" = "$candidate" ]
then
flag=1
fi
done
if [ "$flag" -eq 1 ]
then
echo "The string was found"
else
echo "The string was not found"
fi

BASH: Remove newline for multiple commands

I need some help . I want the result will be
UP:N%:N%
but the current result is
UP:N%
:N%
this is the code.
#!/bin/bash
UP=$(pgrep mysql | wc -l);
if [ "$UP" -ne 1 ];
then
echo -n "DOWN"
else
echo -n "UP:"
fi
df -hl | grep 'sda1' | awk ' {percent+=$5;} END{print percent"%"}'| column -t && echo -n ":"
top -bn2 | grep "Cpu(s)" | \sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | \awk 'END{print 100 - $1"%"}'
You can use command substitution in your first sentence (notice you're creating a subshell in this way):
echo -n $(df -hl | grep 'sda1' | awk ' {percent+=$5;} END{print percent"%"}'| column -t ):

Bash error echo a command

I have a problem. I need to show a echo from a while, I use two echo the first one work but the second it give a error.
#!/bin/bash
conexiuni="/tmp/conexiuni"
if [ "$1" != "" ]; then
netstat -tuan | grep $1 | grep ESTAB | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n > $conexiuni
else
netstat -tuan | grep ESTAB | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n > $conexiuni
fi
cat $conexiuni | while read line
do
con=`echo ''$line'' | awk '{print $1}'`
ip=`echo ''$line'' | awk '{print $2}'`
if [ "$con" -gt "4" ]; then
`echo -e "$ip" >> /var/log/drop_sc_ip`
`echo -e "$ip"`
fi
done
if [ -f "$conexiuni" ];
then
`rm -rf $conexiuni`
fi
The error is :
./show_conn: line 15: 8.97.80.2: command not found
./show_conn: line 15: 8.76.109.13: command not found
./show_conn: line 15: 8.33.15.2: command not found
./show_conn: line 15: 9.118.226.3: command not found
You can write this part without the backticks:
if [ "$con" -gt "4" ]; then
echo -e "$ip" >> /var/log/drop_sc_ip
echo -e "$ip"
fi
also same in this part:
rm -rf $conexiuni
with the backticks, it first executes what is inside the backticks and then tries to execute the output of the backticks.
and change the loop:
while read con ip
do
if [ "$con" -gt "4" ]; then
echo -e "$ip" >> /var/log/drop_sc_ip
echo -e "$ip"
fi
done < $conexiuni

Resources