string comparison with output in Bash - bash

I have a simple script that works great (and prints hello)
variable=false
if [ "$variable" = "false" ]; then
echo hello
fi
However, this does not work (and does not print hello)
variable=$(source script.sh \
| awk -F":" '/maintenanceMode\>/ { print $2i }' \
| sed 's/,//g'
)
echo $variable # prints `false`, as expected
if [ "$variable" = "false" ]; then
echo hello
fi
What am I missing?

Strip whitespaces from your variable.
$variable=`echo $variable | xargs`

Related

If condition for "not equal" is not working as expected in shell script

#!/bin/bash
a=2
b=2
COUNTER=0
sam="abcd"
sam1="xyz"
sam2="mno"
for x in ls | grep .rpm
do
`C=rpm -qpR $x | grep -v CompressedFileNames | grep -v PayloadFilesHavePrefix | wc -l`
if [ "sam2"!="$sam1" ]
then
echo "${sam1}"
echo "${sam2}"
if [ $C -eq $a ]
then
COUNTER=$((COUNTER+1))
echo "${x}"
eval sam=$x
#eval sam1=sam | cut -d '-' -f 1
sam1=`echo "${sam}"| cut -d '-' -f 1`
if [ $COUNTER -eq $b ]
then
break
fi
fi
fi
sam2=`echo "${x}"| cut -d '-' -f 1`
done
This is the output I am getting:
xyz
mno
comps-4ES-0.20050107.x86_64.rpm
comps
comps
comps-4ES-0.20050525.x86_64.rpm
My question is: why is the if condition returning true despite sam1 and sam2 being equal? I have checked for non-equality.
Response is the same even if I use
if [ $C -eq $a ] && [ "$sam2" != " $sam1" ]
As Ansgar Wiechers pointed out, you're missing a "$" in front of the sam2 variable. That way, you're comparing the literal string "sam2" with the string value of $sam1 (which initially is set to "xyz"). What you want to do is compare the string values of both variables:
if [ "$sam2" != "$sam1" ]
Regarding $C, you should only include the commands to be evaluated inside backticks, not the evaluation itself. This is called a command substitution - a subshell is created in which the commands are executed, and the backtick expression is substituted by the computed value. The line should look like this:
C=`rpm -qpR $x | grep -v CompressedFileNames | grep -v PayloadFilesHavePrefix | wc -l`
Your for loop also needs a command substitution: for x in ls | grep .rpm makes it look as if you're piping the output of a for command into grep. What you want to do is iterate over the ls | grep part, which you can do with the following command substitution:
for x in `ls | grep .rpm`
Hi Guys Got the solution:
#!/bin/bash
read -p "enter dep number" a
read -p "enter no of rpms" b
COUNTER=0
sam="abcd"
sam1="xyz"
sam2="mno"
for x in `ls | grep .rpm`
do
C=`rpm -qpR $x |grep -v CompressedFileNames | grep -v PayloadFilesHavePrefix | wc -l`
# echo "${C}:c"
if [ $C -eq $a ] && [ "$sam2" != "$sam1" ]
then
COUNTER=$((COUNTER+1))
# echo "${COUNTER}:counter"
# echo "${x}"
eval sam=$x
#eval sam1=sam | cut -d '-' -f 1
sam1=`echo "${sam}"| cut -d '-' -f 1`
if [ $COUNTER -eq $b ]
then
break
fi
fi
sam2=`echo "${x}"| cut -d '-' -f 1`
#echo "${sam2}"
#echo "${sam1}"
done

How to append the rest of the command from a variable?

In the sample bellow, I would like to print text on the screen and also append this text into file, when the variable cpstdout is set to 1. Otherwise only print the text on screen. I need to have the echo part flexible to the append variable. Is there any way to correct my code?
#!/bin/ksh
cpstdout=1
if [ $cpstdout -eq 1 ]; then
append="| tee somefile"
else
append=""
fi
echo "test string" $append
Now the result is just like this:
./test.sh
test string | tee somefile
-no file is created of course
example of print function:
print_output(){
printf "\t/-------------------------------------------------\\ \n"
for i in "$#"; do
printf "\t| %-14s %-32s |\n" "$(echo $i | awk -F, '{print $1}')" "$(echo $i | awk -F, '{print $2}')"
shift
done
printf "\t\-------------------------------------------------/\n"
}
Define your appending command as a function:
output_with_append() {
tee -a somefile <<<"$1"
}
Then, in the if, set a variable to the appropriate outputting function:
if [ $cpstdout -eq 1 ]; then
output=output_with_append
else
output=echo
fi
Finally, use variable expansion to run the command:
$output "test_string"
Note that I've used tee -a since you said you wanted to append to a file and not overwrite it.
Setting cpstdout to $1 so we can control it through a command-line parameter:
cpstdout="$1"
A example session then looks like this:
$ ./test.sh 1
test_string
$ ./test.sh 1
test_string
$ cat somefile
test_string
test_string
$ ./test.sh 0
test_string
$ cat somefile
test_string
test_string

uppercase first character in a variable with bash

I want to uppercase just the first character in my string with bash.
foo="bar";
//uppercase first character
echo $foo;
should print "Bar";
One way with bash (version 4+):
foo=bar
echo "${foo^}"
prints:
Bar
foo="$(tr '[:lower:]' '[:upper:]' <<< ${foo:0:1})${foo:1}"
One way with sed:
echo "$(echo "$foo" | sed 's/.*/\u&/')"
Prints:
Bar
$ foo="bar";
$ foo=`echo ${foo:0:1} | tr '[a-z]' '[A-Z]'`${foo:1}
$ echo $foo
Bar
To capitalize first word only:
foo='one two three'
foo="${foo^}"
echo $foo
One two three
To capitalize every word in the variable:
foo="one two three"
foo=( $foo ) # without quotes
foo="${foo[#]^}"
echo $foo
One Two Three
(works in bash 4+)
Using awk only
foo="uNcapItalizedstrIng"
echo $foo | awk '{print toupper(substr($0,0,1))tolower(substr($0,2))}'
Here is the "native" text tools way:
#!/bin/bash
string="abcd"
first=`echo $string|cut -c1|tr [a-z] [A-Z]`
second=`echo $string|cut -c2-`
echo $first$second
just for fun here you are :
foo="bar";
echo $foo | awk '{$1=toupper(substr($1,0,1))substr($1,2)}1'
# or
echo ${foo^}
# or
echo $foo | head -c 1 | tr [a-z] [A-Z]; echo $foo | tail -c +2
# or
echo ${foo:1} | sed -e 's/^./\B&/'
It can be done in pure bash with bash-3.2 as well:
# First, get the first character.
fl=${foo:0:1}
# Safety check: it must be a letter :).
if [[ ${fl} == [a-z] ]]; then
# Now, obtain its octal value using printf (builtin).
ord=$(printf '%o' "'${fl}")
# Fun fact: [a-z] maps onto 0141..0172. [A-Z] is 0101..0132.
# We can use decimal '- 40' to get the expected result!
ord=$(( ord - 40 ))
# Finally, map the new value back to a character.
fl=$(printf '%b' '\'${ord})
fi
echo "${fl}${foo:1}"
This works too...
FooBar=baz
echo ${FooBar^^${FooBar:0:1}}
=> Baz
FooBar=baz
echo ${FooBar^^${FooBar:1:1}}
=> bAz
FooBar=baz
echo ${FooBar^^${FooBar:2:2}}
=> baZ
And so on.
Sources:
Bash Manual: Shell Parameter Expansion
Full Bash Guide: Parameters
Bash Hacker's Wiki Parameter Expansion
Inroductions/Tutorials:
Cyberciti.biz: 8. Convert to upper to lower case or vice versa
Opensource.com: An introduction to parameter expansion in Bash
This one worked for me:
Searching for all *php file in the current directory , and replace the first character of each filename to capital letter:
e.g: test.php => Test.php
for f in *php ; do mv "$f" "$(\sed 's/.*/\u&/' <<< "$f")" ; done
Alternative and clean solution for both Linux and OSX, it can also be used with bash variables
python -c "print(\"abc\".capitalize())"
returns Abc
This is POSIX sh-compatible as far as I know.
upper_first.sh:
#!/bin/sh
printf "$1" | cut -c1 -z | tr -d '\0' | tr [:lower:] [:upper:]
printf "$1" | cut -c2-
cut -c1 -z ends the first string with \0 instead of \n. It gets removed with tr -d '\0'. It also works to omit the -z and use tr -d '\n' instead, but this breaks if the first character of the string is a newline.
Usage:
$ upper_first.sh foo
Foo
$
In a function:
#!/bin/sh
function upper_first ()
{
printf "$1" | cut -c1 -z | tr -d '\0' | tr [:lower:] [:upper:]
printf "$1" | cut -c2-
}
old="foo"
new="$(upper_first "$old")"
echo "$new"
Posix compliant and with less sub-processes:
v="foo[Bar]"
printf "%s" "${v%"${v#?}"}" | tr '[:lower:]' '[:upper:]' && printf "%s" "${v#?}"
==> Foo[Bar]
first-letter-to-lower () {
str=""
space=" "
for i in $#
do
if [ -z $(echo $i | grep "the\|of\|with" ) ]
then
str=$str"$(echo ${i:0:1} | tr '[A-Z]' '[a-z]')${i:1}$space"
else
str=$str${i}$space
fi
done
echo $str
}
first-letter-to-upper-xc () {
v-first-letter-to-upper | xclip -selection clipboard
}
first-letter-to-upper () {
str=""
space=" "
for i in $#
do
if [ -z $(echo $i | grep "the\|of\|with" ) ]
then
str=$str"$(echo ${i:0:1} | tr '[a-z]' '[A-Z]')${i:1}$space"
else
str=$str${i}$space
fi
done
echo $str
}
first-letter-to-lower-xc(){
v-first-letter-to-lower | xclip -selection clipboard
}
Not exactly what asked but quite helpful
declare -u foo #When the variable is assigned a value, all lower-case characters are converted to upper-case.
foo=bar
echo $foo
BAR
And the opposite
declare -l foo #When the variable is assigned a value, all upper-case characters are converted to lower-case.
foo=BAR
echo $foo
bar
What if the first character is not a letter (but a tab, a space, and a escaped double quote)? We'd better test it until we find a letter! So:
S=' \"รณ foo bar\"'
N=0
until [[ ${S:$N:1} =~ [[:alpha:]] ]]; do N=$[$N+1]; done
#F=`echo ${S:$N:1} | tr [:lower:] [:upper:]`
#F=`echo ${S:$N:1} | sed -E -e 's/./\u&/'` #other option
F=`echo ${S:$N:1}
F=`echo ${F} #pure Bash solution to "upper"
echo "$F"${S:(($N+1))} #without garbage
echo '='${S:0:(($N))}"$F"${S:(($N+1))}'=' #garbage preserved
Foo bar
= \"Foo bar=

Remove one directory component from path (string manipulation)

I'm looking for the easiest and most readable way to remove a field from a path. So for example, I have /this/is/my/complicated/path/here, and I would like to remove the 5th field ("/complicated") from the string, using bash commands, so that it becomes /this/is/my/path.
I could do this with
echo "/this/is/my/complicated/path/here" | cut -d/ -f-4
echo "/"
echo "/this/is/my/complicated/path/here" | cut -d/ -f6-
but I would like this done in just one easy command, something that would like
echo "/this/is/my/complicated/path" | tee >(cut -d/ -f-4) >(cut -d/ -f6-)
except that this doesn't work.
With cut, you can specify a comma separated list of fields to print:
$ echo "/this/is/my/complicated/path/here" | cut -d/ -f-4,6-
/this/is/my/path/here
So, it's not really necessary to use two commands.
How about using sed?
$ echo "/this/is/my/complicated/path/here" | sed -e "s%complicated/%%"
/this/is/my/path/here
This removes the 5th path element
echo "/this/is/my/complicated/path/here" |
perl -F/ -lane 'splice #F,4,1; print join("/", #F)'
just bash
IFS=/ read -a dirs <<< "/this/is/my/complicated/path/here"
newpath=$(IFS=/; echo "${dirs[*]:0:4} ${dirs[*]:5}")
Anything wrong with a bash script?
#!/bin/bash
if [ -z "$1" ]; then
us=$(echo $0 | sed "s/^\.\///") # Get rid of a starting ./
echo " "Usage: $us StringToParse [delimiterChar] [start] [end]
echo StringToParse: string to remove something from. Required
echo delimiterChar: Character to mark the columns "(default '/')"
echo " "start: starting column to cut "(default 5)"
echo " "end: last column to cut "(default 5)"
exit
fi
# Parse the parameters
theString=$1
if [ -z "$2" ]; then
delim=/
start=4
end=6
else
delim=$2
if [ -z "$3" ]; then
start=4
end=6
else
start=`expr $3 - 1`
if [ -z "$4" ]; then
end=6
else
end=`expr $4 + 1`
fi
fi
fi
result=`echo $theString | cut -d$delim -f-$start`
result=$result$delim
final=`echo $theString | cut -d$delim -f$end-`
result=$result$final
echo $result

problem in using awk

i couldn't solve this. when i execute this program i get the following error
" line 7: unexpected EOF while looking for matching `'' "
a=115292a1504606846976ULL
b=2
if [ "$b" = "2" ]; then
var1=`echo $a | awk -F"U" '\
{
var2=`echo $var1 | awk -F"a"
{print " "$2}'`
}\
fi
Update: from other, recently closed question
To be more specific, this is my project code
if [ "$FORMAT" = "java" ]; then
cat $INPUT_FILE | awk -F":" '\
/^$/ { print "" }\
/^\/\/.*/ { print " "$0}\
/:string:/ { print " public static final String "$1" = "$3";" }\
/:char:/ { print " public static final char "$1" = "$3";" }\
/:ullong:/ { print " public static final long "$1" = "$3";" }\
/:ulong:/ { print " public static final int "$1" = "$3";" }\
/:long:/ { print " public static final int "$1" = "$3";" }\
' >> $CONST_FILE
fi;
Now i need to truncate $3 (this value is actually read from another file) into two parts(only for ullong). lets say
$3=1256985361455ULL
i need to truncate into 1256985361455 and ULL. (only when it is ullong)
please help me out in this issue.
i tried using another awk inside the the following, but ended up in chaos.
/:ullong:/ { print " public static final long "$1" = "$3";" }\
If you expect the value of $3 for the ullong records to be something like "1256985361455ULL" then
/:ullong:/ {
sub(/ULL$/, "", $3)
print " public static final long "$1" = "$3";"
}
Your quoting problem is because once you start a back-quoted command, it continues until the next back-quote. This is your code as shown above, except I've removed the blank lines.
a=115292a1504606846976ULL
b=2
if [ "$b" = "2" ]; then
var1=`echo $a | awk -F"U" '\
{
var2=`echo $var1 | awk -F"a"
{print " "$2}'`
}\
fi
(Back-quotes '`' are hard to show in in-line Markdown.)
The line var1= line starts a back-quoted expression, which stops at the next unescaped back-quote, which is the one after var2=. It then reads the rest of that line, and on the following line, encounters a single quote. When it looks for the following single quote, there is none - so it reports an error. You can demonstrate this is what goes on in steps:
a=115292a1504606846976ULL
b=2
if [ "$b" = "2" ]; then
var1=`echo $a | awk -F"U" '\
{
var2=\`echo $var1 | awk -F"a"
{print " "$2}'`
}\
fi
The script above has an escape (backslash) before the back-quote after var2=, so now the command in back-quotes extends to the back-quote after the print line. This still isn't valid shell; the line with }\ combines with the fi to make a command name }fi, so you still get an unexpected EOF error - because the fi for the end of the if is missing. Modify the script again:
a=115292a1504606846976ULL
b=2
if [ "$b" = "2" ]; then
var1=`echo $a | awk -F"U" '\
{
var2=\`echo $var1 | awk -F"a"
{print " "$2}'`
#}\
fi
This comments out the close brace, and the shell script is now 'valid'; it is awk's turn to start complaining about the invalid script it is given.
++ awk -FU '{
var2=`echo $var1 | awk -F"a"
{print " "$2}'
awk: syntax error at source line 2
context is
>>> var2=` <<<
awk: illegal statement at source line 2
awk: illegal statement at source line 2
missing }
Other people have given you roughly what you need as an answer. I'd probably use Perl to do the splitting up (and I suspect I could lose the intermediate array #x if I spent enough time on it, producing a script of line noise):
a=115292a1504606846976ULL
b=2
if [ "$b" = "2" ]
then var1=$(echo $a | perl -ne '#x=split /[aU]/; print "$x[1]\n"')
fi
However, you can also do it in one line with awk, thus:
a=115292a1504606846976ULL
b=2
if [ "$b" = "2" ]
then var1=$(echo $a | awk -Fa '{sub("ULL","",$2); print $2}')
fi
This splits the input on the 'a' instead of the 'U'; it then removes the 'ULL' from the second field and prints it. If you want to split on 'U', then you use:
a=115292a1504606846976ULL
b=2
if [ "$b" = "2" ]
then var1=$(echo $a | awk -FU '{sub("[0-9]+a", "", $1); print $1}')
fi
The regular expression in the sub is marginally more complex this way.
Not sure exactly what you are trying to do, but this slight re-write printed out the middle part of a (which is I think what you wanted)
> cat moo.sh
a=115292a1504606846976ULL
b=2
if [ "$b" = "2" ]; then
var1=`echo $a | awk -F"U" '{print $1}'`
var2=`echo $var1 | awk -F"a" '{print " "$2}'`
echo $var2
fi
> sh moo.sh
1504606846976
You can't do shell commands inside awk except to make system calls. without you telling us what you are trying to achieve
#!/bin/bash
a=115292a1504606846976ULL
b=2
case "$b" in
2 )
a=${a%U*}
echo ${a#*a} # I assume you want to get 1504606846976
esac
a=115292a1504606846976ULL
b=2
if [ "$b" = "2" ]; then
var1=`echo $a | awk -F "U" '{print $1}' | awk -F "a" '{print $2}'`
fi

Resources