bash with cut to get a value with carriage return \r - bash

Consider the following bash script
NP=`grep nprocshared $GF | cut -d '=' -f2`
echo $NP
if [ $N -ne $NP ]; then
echo "Error"
Please note the $N is an integer and it is fine! The file contains
%nprocshared=6
%mem=12GB
...
With the set -x option, I see this in the output
++ grep nprocshared file.gjf
++ cut -d = -f2
+ NP=$'6\r'
+ echo $'6\r'
6
+ '[' 4 -ne $'6\r' ']'
So, I expect 4ne6, but I don't see that. What it reads the 6 as 6\r?

NP=`grep nprocshared $GF | cut -d '=' -f2 | tr -d \\r`
echo $NP
if [ $N -ne $NP ]; then
echo "Error"
VoilĂ .
Or, even better, since NP is always a number:
NP=`grep nprocshared $GF | tr -dc 0-9`
echo $NP
if [ $N -ne $NP ]; then
echo "Error"

Related

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

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

I cannot seem to run this properly... It stucks and does not display an output

Here's my script:
while [[ $startTime -le $endTime ]]
do
thisfile=$(find * -type f | xargs grep -l $startDate | xargs grep -l $startTime)
fordestination=`cut -d$ -f2 $thisfile | xargs cut -d ~ -f4`
echo $fordestination
startTime=$(( $startTime + 1 ))
done
I think your cut and grep commands could get stuck. You probably should make sure that their parameters aren't empty, by using the [ -n "$string" ] command to see if $string isn't empty. In your case, if it were empty, it wouldn't add any files to the command that would use it afterwards, meaning that the command would probably wait for input from the command line (ex: if $string is empty and you do grep regex $string, grep wouldn't receive input files from $string and would instead wait for input from the command line). Here's a "complex" version that tries to show where things could go wrong:
while [[ $startTime -le $endTime ]]
do
thisfile=$(find * -type f)
if [ -n "$thisfile" ]; then
thisfile=$(grep -l $startDate $thisfile)
if [ -n "$thisfile" ]; then
thisfile=$(grep -l $startTime $thisfile)
if [ -n "$thisfile" ]; then
thisfile=`cut -d$ -f2 $thisfile`
if [ -n "$thisfile" ]; then
forDestination=`cut -d ~ -f4 $thisfile`
echo $fordestination
fi
fi
fi
fi
startTime=$(( $startTime + 1 ))
done
And here's a simpler version:
while [[ $startTime -le $endTime ]]
do
thisfile=$(grep -Rl $startDate *)
[ -n "$thisfile" ] && thisfile=$(grep -l $startTime $thisfile)
[ -n "$thisfile" ] && thisfile=`cut -d$ -f2 $thisfile`
[ -n "$thisfile" ] && cut -d ~ -f4 $thisfile
startTime=$(( $startTime + 1 ))
done
The "-R" tells grep to search files recursively, and the && tells bash to only execute the command that follows it if the command before it succeeded, and the command before the && is the test command (used in ifs).
Hope this helps =)

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

Resources