Cshell and Awk Infinite Running - unix

When I run the below program, I get no return, however the program still runs forever until I end it. Can some one please exoplain to me why this would happen. I am trying to get this complex awk statement to work, however, have been very unsuccessful.
The code I am using for my Cshell is (its all on one line, but I split it here to make it easier to read):
awk '{split($2,b,""); counter = 1; while (counter < 13)
{if (b[counter] == 1 && "'$cmonth'" > counter)
{{printf("%s%s%s\n", $1, "'$letter'","'$year3'")}; counter++;
else if (b[counter] == 1 && "'$cmonth'" <= counter)
{{printf("%s%s%s\n", $1, "'$letter'","'$year2'")}; counter++;}
else echo "fail"}}' fileRead >> $year$month
The text file I am reading from looks like
fff 101010101010
yyy 100100100100
Here $year2 and $year3 represent counters that start from 1987 and go up 1 year for each line read.
$cmonth is just a month counter from 1–12.
$letter is just a ID.
The goal is for the program to read each line and print out the ID, month, and year if the position in the byte code is 1.

You have some mismatched curly braces, I have reformatted to one standard of indentation.
awk '{ \
split($2,b,""); counter = 1 \
while (counter < 13) { \
if (b[counter] == 1 && "'$cmonth'" > counter){ \
printf("%s%s%s\n", $1, "'$letter'","'$year3'") \
counter++ \
} \
else if (b[counter] == 1 && "'$cmonth'" <= counter) { \
printf("%s%s%s\n", $1, "'$letter'","'$year2'") \
counter++ \
} \
else print "fail" \
} # while \
}' fileRead >> $year$month
Also awk does'nt support echo.
Make sure that the \ is the LAST char on the line (no space or tab chars!!!), or you'll get a syntax error.
Else, you can 'fold' up all of the lines into one line. adding the occasional ';' as needed.
edit
OR you can take the previous version of this awk script (without the \ line continuation chars), put it in a file (without any of the elements outside of the ' ....' (single quotes) and call it from awk as a file. You'll also need to made so you can pass the variables cmonth, letter, year2 and any others that I've missed.
save as file
edit file, remove any `\' chars, change all vars like "'$letter'" to letter **
call program like
**
awk -v letter="$letter" -v year2="$year2" -v month="$month" -f myScript fileRead >> $year$month
**
for example
printf("%s%s%s\n", $1, "'$letter'","'$year2'")
becomes
printf("%s%s%s\n", $1, letter,year2)
IHTH.

Related

AWK print unexpected newline or end of string inside shell

I have a shell script which is trying to trim a file from end of the line but I always get some error.
Shell Script:
AWK_EXPRESSION='{if(length>'"$RANGE1"'){ print substr('"$0 "',0, length-'"$RANGE2"'}) } else { print '"$0 "'} }'
for report in ${ACTUAL_TARGET_FOLDER}/* ; do
awk $AWK_EXPRESSION $report > $target_file
done
If I trigger the AWK command, I get unexpected newline or end of string near print.
What am I missing?
Why are you trying to store the awk body in a shell variable? Just use awk and the -v option to pass a shell value into an awk variable:
awk -v range1="$RANGE1" -v range2="$RANGE2" '{
if (length > range1) {
print substr($0,0, length-range2)
} else {
print
}
}' "$ACTUAL_TARGET_FOLDER"/* > "$target_file"
Add a few newlines to help readability.
Get out of the habit of using ALLCAPS variable names, leave those as reserved by the shell. One day you'll write PATH=something and then wonder why your script is broken.
Unquoted variables are subject to word splitting and glob expansion. Use double quotes for all your variables unless you know what specific side-effect you want to use.
I would recommend writing the AWK program using AWK variables instead of interpolating variables into it from the shell. You can pass variable into awk on the command line using the -v command line option.
Also, awk permits using white space to make the program readable, just like other programming languages. Like this:
AWK_EXPRESSION='{
if (length > RANGE1) {
print substr($0, 1, length-RANGE2)
} else {
print
}
}'
for report in "${ACTUAL_TARGET_FOLDER}"/* ; do
awk -v RANGE1="$RANGE1" -v RANGE2="$RANGE2" "$AWK_EXPRESSION" "$report" > "$target_file"
done

For loop variable is empty in gmake

I have a list of header files created thus:
expand=$(1)/$(1).h
HDRS=$(foreach x, $(DIRS), $(call expand,$(x)))
Which yields a list like a/a.h b/b.h ...
but when I use this in a for loop:
for i in $(HDRS) ; do \
echo $$i \
cp $$i $(some_dir) \
done
$$i is empty. And the cp fails, having only one argument.
The usual variants of $$i ( $i, $$i, $(i), ${i} ), don't change anything, nor do the usual variants of $(HDRS) ("$(HDRS)", etc.).
gmake echos the for-loop as
for i in a.h b.h ; \
do \
echo $i \
cp $i somedir \
done
Which looks correct.
But the implicit bash shell emits an error "/bin/sh -c: line 5: syntax error: unexpected end of file"
gmake then exits due to the failed command.
Due to the \, make emits the recipe as a single line. This confuses the shell. Try this instead, using ; in place of the line terminator:
for i in a.h b.h ; \
do \
echo $i ; \
cp $i somedir ; \
done

What is "c==0 { c=0;system("cat") }" in AWK

I found this command in dockerfile like below.
echo -e 'skip-host-cache\nskip-name-resolve' | awk '{ print } $1 == "[mysqld]" && c == 0 { c = 1; system("cat") }' /etc/my.cnf > /tmp/my.cnf
I couldn't undersand it.
The awk program prints each line from the input file. If it finds the first line that starts with [mysqld], it uses the system command cat to print the text from the pipe.
Personally, I would use something like this:
awk -v add='skip-host-cache\nskip-name-resolve' \
'{ print } $1 == "[mysqld]" && found == 0 { print add; found = 1; }' my.cnf

Escape awk command

I have got a unix(aix) command which includes a small awk script. It works and here it is...
ps -eaf | awk 'ARGIND == 1 {$pids[$0] = 1} ARGIND > 1 {if ($2 in pids) printf("%s\n",$0)}' /home/richard/myFile.flg -
When I run this command from a different box using ssh it doesn't work.
ssh myuser#myOtherBox ps -eaf | awk 'ARGIND == 1 {$pids[$0] = 1} ARGIND > 1 {if ($2 in pids) printf("%s\n",$0)}' /home/richard/myFile.flg -
I've worked out that I need to quote the awk script and escape some characters in the awk command but I can't get the escapes right.
Would someone pls help me with quoting the awk part of the script and escaping what is required.
thanks
What happens when you execute
ssh myuser#myOtherBox ps -eaf | ...
is that ps -eaf is run on the other box, and the output is returned; ssh then writes the output it receives to its own stdout, which is (locally) redirected through the command ...; in this case, an awk command.
Unfortunately, (I assume) /home/richard/myFile.flg is on the remote mache and not the local machine, so the awk command fails.
To get the whole thing to run on the remote machine, you need to provide it as a single argument; one way which doesn't require much quoting effort is to use a here-doc:
ssh myuser#myOtherBox "$(cat<<"END"
ps -eaf |
awk 'ARGIND == 1 {pids[$0] = 1}
ARGIND > 1 {if ($2 in pids) printf("%s\n",$0)}' \
/home/richard/myFile.flg -
END
)"
Note that printf("%s\n",$0) is really just a complicated way of writing print, so you could simplify the remote command quite a bit. But you would still need to deal with the single quotes in the awk command:
ssh myuser#myOtherBox '
ps -eaf |
awk '"'"'ARGIND == 1 {pids[$0] = 1; next}
$2 in pids {print}'"'"' \
/home/richard/myFile.flg -'
To understand '"'"', you need to break it into pieces:
' close '-quoted string
"'" A (quoted) '
' open another '-quoted string
In cases like this you need double escaping, this should work:
ssh myuser#myOtherBox "ps -eaf | awk \"ARGIND == 1 {\\\$pids[\\\$0] = 1} ARGIND > 1 {if (\\\$2 in pids) printf(\\\"%s\n\\\",\\\$0)}\" /home/richard/myFile.flg -"
If you can use bash's $'STRING' syntax, then things remain quite
readable; in this case one only has to escape the single-quotes and
backslashes:
$'ps -eaf |
awk \'
ARGIND == 1 {$pids[$0] = 1}
ARGIND > 1 {if ($2 in pids) printf("%s\\n",$0)}\' /home/richard/myFile.flg -'

HP-Unix: C-shell:Disk space checking

I have 10 devices that using hp-ux and i want to check the disk space in each devices.
my requirement is if the space more than 90%, the info of device ans space will be save to a log.
this is list of device and ip address which i set as variable ipadd:
lo1 100.45.32.43
lot2 100.45.32.44
lot3 100.45.32.44
lot4 100.45.32.45
lot5 100.45.32.46
and so on..
This is my script so far :
#!/bin/csh -f
set ipaddress = (`awk '{print $2}' "ipadd"`)
set device = (`awk '{print $1}' "ipadd"`)
# j = 1
while ($j <= $#ipaddress)
echo $ipaddress
set i = 90 # Threshold set at 90%
set max = 100
while ($i <= $max)
rsh $ipaddress[$j] bdf | grep /dev/vg00 | grep $i% \
|awk '{ file=substr($6,index($6,"/") + 1,length($6)); print "WARNING: $device[$j]:/" file " has reached " $5 ". Perform HouseKeeping IMMEDIATELY..." >> "/scripts/space." file ".file"}'
# i++
end
# j++
end
The output after bdf:
/dev/vg00/lvol2 15300207 10924582 28566314 79% /
/dev/vg00/lvol4 42529 23786 25510 55% /stand
The output at terminal after exec the script:
100.45.32.43
100.45.32.44
The output at .file:
WARNING: $device[$j]:/ has reached 79%. Perform HouseKeeping IMMEDIATELY...
My question is, is it my looping have something wrong cause only iterates one time only because my .file output only show one device only?
And why $device[$j] not come out in .file output?
or awk have problem?
Thank you for the advice.
Your code tested for each possible percentage between 90 and 100.
Persumably, you'd be OK with code that checks once, and asks 'is device percent greater than 90%'?. So then you don't need the inner loop at all, and you make only 1 connection per machine, try
#!/bin/csh -f
set ipaddress = (`awk '{print $2}' "ipadd"`)
set device = (`awk '{print $1}' "ipadd"`)
# j = 1
set i = 90 # Threshold set at 90%
while ($j <= $#ipaddress)
echo $ipaddress
echo "#dbg: ipaddress[$j]=${ibpaddress[$j]}"
rsh $ipaddress[$j] bdf \
| awk -v thresh="$i" -v dev="$device[$j]" \
'/\/dev\/vg00/ { \
sub(/%/,"",$5) \
if ($5 > thresh) { \
file=substr($6,index($6,"/") + 1,length($6)) \
print "WARNING: " dev ":/" file " has reached " $5 ". Perform HouseKeeping IMMEDIATELY..." >> "/scripts/space." file ".file" \
}\
}'
# j++
end
Sorry, but I don't have a csh available to dbl-chk for syntax errors.
So here is a one liner that we determined worked in your environment.
rsh $ipaddress[$j] bdf | nawk -v thresh="$i" -v dev="$device[$j]" '/\/dev\/vg00/ { sub(/%/,"",$5) ; if ($5 > thresh) { file=substr($6,index($6,"/") + 1,length($6));print "#dbg:file="file; print "WARNING: " dev ":/" file " has reached " $5 ". Perform HouseKeeping IMMEDIATELY..." >> "/scripts/space.file.TMP" } }'
I don't have a system with bdf available. Change the two references to $5 in the sub() and if test to match the field-number of the output that has the percentage you want to test.
Note that -v var="value" is the standard way to pass a variable value from the shell to an awk script that is enclosed in single-quotes.
Be careful that any '\' chars at the end of a line are the last chars, no trailing space or tabs, or you'll get an indecipherable error msg. ;-)
IHTH

Resources