awk: syntax error near unexpected token `(' - bash

I tried to assign the output of an awk command to a variable:
USERS=$(awk '/\/X/ {print $1}' <(w))
This line is part of the following script:
#!/bin/sh
INTERFACE=$1 # The interface which is brought up or down
STATUS=$2 # The new state of the interface
case "$STATUS" in
up) # $INTERFACE is up
if pidof dropbox; then
killall dropbox
fi
USERS=$(awk '/\/X/ {print $1}' <(w))
for user in $USERS; do
su -c "DISPLAY=$(awk '/\/X/ {print $11}' <(w)) dropboxd &" $user
done
;;
down) # $INTERFACE is down
;;
esac
However, I get the following error:
script: command substitution: line 14: syntax error near unexpected token `('
script: command substitution: line 14: `awk '/\/X/ {print $1}' <(w))'
All brackets are closed. Where is the syntax error?

I'm assuming because you are using #!/bin/sh and not #!/bin/bash that process substitution is not available (or you have a version of bash that doesn't support process subsitiution, pre 4.X.X). Switch to bash or just pipe w to your awk command:
USERS=$(w | awk '/\/X/ {print $1}')

Related

Bash: Complex command in if statement

I'm writing this script, which should detect an error after the smart test is done. But I can't get it to detect any error, or not of course.
if [[ smartctl --log=selftest /dev/sda | awk 'NR>7 {print $4,$5,$6,$7}' | sed 's/offline//g; s/00%//g' != *"Completed without error"* ]; then
echo "No error detected"
else echo "Error detected"
fi
Output:
./test.sh: line 19: conditional binary operator expected
./test.sh: line 19: syntax error near `--log=selftest'
./test.sh: line 19: `if [[ smartctl --log=selftest /dev/sda | awk 'NR>7 {print $4,$5,$6,$7}' | sed 's/offline//g; s/00%//g' != *"Completed without error"* ]]; then'
So obviously I'm doing something wrong. But all the tutorials say two [[]] thingies, but I think the command is quite complex, it doesn't work... How can I make it work?
If you want to do a substring comparison, you need to pass a string on the left-hand side of the = or != operator to [[ ]].
A command substitution, $(), will replace the command it contains with its output, giving you a single string which can be compared in this way.
That is:
smartctl_output=$(smartctl --log=selftest /dev/sda | awk 'NR>7 {print $4,$5,$6,$7}' | sed 's/offline//g; s/00%//g')
if [[ "$smartctl_output" != *"Completed without error"* ]; then
: ...put your error handling here...
fi
or, a bit less readably:
if [[ "$(smartctl --log=selftest /dev/sda | awk 'NR>7 {print $4,$5,$6,$7}' | sed 's/offline//g; s/00%//g')" != *"Completed without error"* ]; then
: ...put your error handling here...
fi
You are confusing things. If the command you want to test is smartctl, don't replace it with [[. You want either or, not both. (See also e.g. Bash if statement syntax error)
Anyway, piping awk through sed and then using the shell to compare the result to another string seems like an extremely roundabout way of doing things. The way to communicate with if is to return a non-zero exit code for error.
if smartctl --log=selftest /dev/sda |
awk 'NR>7 { if ($4 OFS $5 OFS $6 OFS $7 ~ /Completed without error/) e=1; exit }
END { exit 1-e }'
then
echo "No error detected"
else
echo "Error detected"
fi

bash / Variable value is empty after the loop

I'm new to bash and try a simple loop but the value of my variable is being lost after it and I can not understand why - I have looked at few similar issues but they are all related to subshell execution of a while loop . I'm not doing but still facing issues - can someone explain me where is my mistake ?
#!/bin/bash
check_ss ()
{
command_list | awk '{print $1 $9}' > ss.out
for i in {1..8}
do grep -Pa "\x3$i" ss.out > ss$i.out
if grep -w "NotStarted" ss$i.out
then
ss$i=0
else
ss$i=1
fi
done
}
check_ss
echo $ss1
echo $ss2
echo $ss3
echo $ss4
I'm getting this on execution :
[root#lubo ~]# ./ss.sh
./ss.sh: line 21: ss1=1: command not found
./ss.sh: line 21: ss2=1: command not found
./ss.sh: line 21: ss3=1: command not found
./ss.sh: line 21: ss4=1: command not found
./ss.sh: line 21: ss5=1: command not found
./ss.sh: line 21: ss6=1: command not found
./ss.sh: line 21: ss7=1: command not found
./ss.sh: line 21: ss8=1: command not found
Thanks in advance
You need to use declare to dynamically construct a variable name.
declare "ss$i=0"
An array would be a better alternative to dynamic variable names.
check_ss() {
ss=()
command_list | awk '{print $1 $9}' > ss.out
for i in {1..8}; do
grep -Pa "\x3$i" ss.out > ss$i.out
if grep -w "NotStarted" ss$i.out; then
ss[$i]=0
else
ss[$i]=1
fi
done
}
check_ss
echo ${ss[1]}
echo ${ss[2]}
echo ${ss[3]}
echo ${ss[4]}
You could also get rid of the temporary files.
check_ss() {
ss=()
command_list | awk '{print $1 $9}' > ss.out
for i in {1..8}; do
if grep -Pa "\x3$i" ss.out | grep -w "NotStarted"; then
ss[$i]=0
else
ss[$i]=1
fi
done
}
I don't know what your input looks like exactly, but you might even be able to simplify it further to something like:
check_ss() {
ss=()
while read i; do
ss[$i]=1
done < <(command_list | awk '$9=="NotStarted" {print $1}')
}
or if you just want a list of the NotStarted numbers,
ss=(command_list | awk '$9=="NotStarted" {print $1}')
echo "${ss[#]}"

Solaris - Comment Specific Line from File and Add New One

I haven't worked much with solaris, but I'm supposed to be writing a script that searches for a line in a file, comments it out, and writes the correct line below it.
for i in `cat solarishosts`
do
#print hostname
echo ${i}
#get the line number of the expression after the /; save its value to linenum
linenum="$(ssh -o ConnectTimeout=1 -o ConnectionAttempts=1 ${i} "awk '/%sugrp ALL=\(user\) lines: /usr/bin/su -, /usr/bin/su - user/a{ print NR; exit }' /usr/local/etc/sudoers")"
#overwrite the line # linenum (overwriting just a to add a comment)
ssh -o ConnectTimeout=1 -o ConnectionAttempts=1 ${i} "sed -n "${linenum}"p <<< "#%sugrp ALL=\(user\) lines: /usr/bin/su -, /usr/bin/su - user""
#use the linenum var to make a newlinenum var , this one being one line down from where the commented text was written
newlinenum=linenum+1
#write the line in quotes # the newlinenum position
ssh -o ConnectTimeout=1 -o ConnectionAttempts=1 ${i} "sed -n "${newlinenum}"p <<< "%sugrp ALL=\(ALL\) ALL""
done
I'm getting weird errors :
awk: syntax error near line 1
awk: bailing out near line 1
bash: -c: line 0: syntax error near unexpected token `newline'
bash: -c: line 0: `sed -n p <<< #%sugrp ALL=(user) PASSWD: /usr/bin/su -, /usr/bin/su - user'
bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `sed -n linenum+1p <<< %sugrp ALL=(ALL) ALL'
It looks like there's an error with my awk syntax ... but it isn't on line 1? And I'm not sure what the error is
I don't have a newline character anywhere in my first sed line?
In my code I escaped the "(' it's complaining about
That's pretty messy. You don't need to ssh into the box 3 times. Your quoting is a big problem. And you never actually write the changes back to the file.
Try this: build up the remote command and call ssh once:
line='%sugrp ALL=(user) lines: /usr/bin/su -, /usr/bin/su - user'
newline='%sugrp ALL=(ALL) ALL'
file=/usr/local/etc/sudoers
awkcmd='$0 == line {print "#" $0; print new}'
cmd=$(
printf "awk -v line='%s' -v new='%s' '%s' %s > %s.new && mv %s %s.bak && mv %s.new %s" \
"$line" \
"$newline" \
"$awkcmd" \
"$file" "$file" "$file" "$file" "$file" "$file"
)
while read -r host; do
echo "$host"
# perform the remote command
ssh -o ConnectTimeout=1 -o ConnectionAttempts=1 "$host" sh -c "$cmd"
done < solarishosts
I use single quotes as much as possible to reduce the need for backslashes in the constant strings, and all variables are quoted when used.

error in awk of shell script

I am getting the below error ith my code.What is missing in it? My goal is to print 13.0.5.8 in $version
#!/bin/ksh
file="abc_def_APP_13.0.5.8"
if echo "$file" | grep -E "abc_def_APP"; then
echo "Version found: $file"
version1=(echo $file | awk -F_ '{print $NF}' | cut -d. -f1-3)
version2=(echo $file | awk -F_ '{print $NF}' | cut -d. -f4-)
echo $version1
echo $version2
version=$version$version2
echo $version
else
echo "Version not found"
fi
Please find below the error:
./version.sh: line 7: syntax error near unexpected token `|'
./version.sh: line 7: ` version1=(echo $file | awk -F_ '{print $NF}' | cut -d. -f1-3)'
./version.sh: line 9: syntax error near unexpected token `|'
./version.sh: line 9: ` version2=(echo $file | awk -F_ '{print $NF}' | cut -d. -f4-)'
./version.sh: line 18: syntax error near unexpected token `else'
There's no need for awk at all. Just trim every character before the last underscore, like so:
file="abc_def_APP_13.0.5.8"
version="${file##*_}"
echo "$version"
See http://mywiki.wooledge.org/BashFAQ/073 for documentation on this technique, or see "parameter expansion" in bash's own docs.
To treat the last segment separately is also straightforward:
file="abc_def_APP_13.0.5.8"
version="${file##*_}" # result: 13.0.5.8
version_end="${version##*.}" # result: 8
version_start="${version%.*}" # result: 13.0.5
echo "${version_start}/${version_end}" # result: 13.0.5/8
Because this happens internally to bash, without executing any external commands (such as awk), it should be considerably faster to execute than other approaches given.
The problem is your backticks are missing $ you need to fix the following two lines like so:
version1=$(echo $file | awk -F_ '{print $NF}' | cut -d. -f1-3)
version2=$(echo $file | awk -F_ '{print $NF}' | cut -d. -f4-)
This will fix the syntactical errors. The following line doesn't make much sense as $version hasn't been initialize yet:
version=$version$version2
Did you mean:
version="${version1}.${version2}"
A side note you are using the -E option with grep but you aren't using any extended regexp features, in fact you are doing a fixed string string search so -F is more appropriate. You probably also want to use the -q option to suppress the output from grep.
Personally I would do:
file="abc_def_APP_13.0.5.8"
echo "$file" | awk '/abc_def_APP/{print "Version found: "$0;
print $4,$5,$6;
print $7;
print $4,$5,$6,$7;
next}
{print "Version not found"}' FS='[_.]' OFS=.
If you just want the version number in the variable version then why not simply:
version=$(echo "$file" | grep -o '[0-9].*')
It can all be done in a single awk command and without additional cut command. Consider following command:
read version1 version2 < <(echo $file|awk -F "[_.]" '{
printf("%s.%s.%s ", $4, $5, $6); printf("%s", $7);
for (i=8; i<=NF; i++) printf(".%s", $i); print ""}')
echo "$version1 :: $version2"
OUTPUT
13.0.5 :: 8

Syntax error near unexpected token `done'

I run my shell script but return a error "syntax error near unexpected token `done'", I wonder why it is ? The important thing is I can run it in another computer...
See my code below:
input=$1
folder=$2
output=$3
while read line
do
url=`echo $line | awk -F'\t' '{print $2}'`
id=`echo $line | awk -F'\t' '{print $2}' | sed 's/http:\/\/buy.yahoo.com.tw\/gdsale\/gdsale.asp?gdid=//g'`
ans=`echo $line | awk -F'\t' '{print $3}'`
flag=`grep "$ans" $folder/$id".spec"`
if [ -n "$flag" ]; then
echo "yes $line" >> $3
else
echo "no $line" >> $3
fi
done < $input
Thanks!
If it runs on one machine but not another, then there are differences in the script files on the different machines. Perhaps you have different line endings on one machine -- check them both with dos2unix

Resources