Thursday, March 17, 2011

File descriptors for read loops...

while read with a command that eats input (ssh, another read etc)

for file:


$ cat $tempfile
a b
c d
e f
g h


In ksh:


#!/bin/ksh

exec 4<$tempfile
while read -u4 first second
do
  echo first=$first
  echo second=$second
  printf "number?: "
  read NUM
  echo "name=$NUM"
  ssh localhost uname 2>/dev/null
done


in bash:


#!/bin/bash

exec 4<$tempfile
while read <&4 first second
do
  echo first=$first
  echo second=$second
  printf "number?: "
  read NUM
  echo "name=$NUM"
  ssh localhost uname 2>/dev/null
done

exec 4<&-


ksh: http://unix.derkeiler.com/Newsgroups/comp.unix.shell/2003-05/0889.html

bash: http://forums.devshed.com/unix-help-35/bash-scripting-using-file-descriptors-154812.html

Wednesday, March 16, 2011

Repeat after me, awk is not Perl...

What does a semicolon mean to awk?

This works:

$ /usr/bin/ps -ef | awk '/ root\ /{p++};END{print p}'


but this doesn't:

$ /usr/bin/ps -ef | awk 'BEGIN{p=0};/ root\ /{p++}END{print p}'
awk: syntax error near line 1
awk: bailing out near line 1


and this does:

$ /usr/bin/ps -ef | awk 'BEGIN{p=0}/ root\ /{p++}END{print p}'
0


and just to prove it's REALLY niggly, it's fussy about the order you give it things too:


$ /usr/bin/ps -ef | awk '/ root\ /{p++}BEGIN{p=0}END{print p}'
awk: syntax error near line 1
awk: bailing out near line 1


while this works fine:


$ /usr/bin/ps -ef | awk 'BEGIN{p=0}END{print p}'
0

Wednesday, March 02, 2011

Backticks can be dangerous!

For years I've preferred to use

$(command)

rather than

`command`

while shell scripting.

For me it was mostly a matter of style, but I pretty much thought that the two were equivalents.
I felt it was a bit easier to see $(...) than `...` and sometimes I need to nest commands with:

$(command $(othercommand))

which would be impossible with backticks.

THEY ARE NOT THE SAME!


#!/bin/ksh
#
#
#

for STRING in 'sample.txt' 'File: C:\\path\\to\\file.txt|Something else'
do

printf "result: "
echo "$STRING" | sed 's/^[^|]*\\\([^\\]*\)|.*$/\1/g'
echo 1
VAR_1=$(echo "$STRING" | sed 's/^[^|]*\\\([^\\]*\)|.*$/\1/g')
echo 2
VAR_2=`echo "$STRING" | sed 's/^[^|]*\\\([^\\]*\)|.*$/\1/g'`
echo 3
VAR_3=`echo "$STRING" | sed "s/^[^|]*\\\([^\\]*\)|.*$/\1/g"`
echo 4
VAR_4=`echo "$STRING" | sed 's/^[^|]*\\\\\([^\\]*\\)|.*$/\1/g'`

cat <<EOT
VAR_1: '$VAR_1'
VAR_2: '$VAR_2'
VAR_3: '$VAR_3'
VAR_4: '$VAR_4'
EOT

done


Don't blame ksh, it does the same in bash and Bourne shell.
(although $( ) syntax is not valid in Bourne shell)

Solaris:

$ uname -a
SunOS umurxd04 5.10 Generic_137138-09 i86pc i386 i86pc
$ ./try.sh
result: sample.txt
1
2
sed: command garbled: s/^[^|]*\\([^\]*\)|.*$/\1/g
3
4
VAR_1: 'sample.txt'
VAR_2: ''
VAR_3: 'sample.txt'
VAR_4: 'sample.txt'
result: file.txt
1
2
sed: command garbled: s/^[^|]*\\([^\]*\)|.*$/\1/g
3
4
VAR_1: 'file.txt'
VAR_2: ''
VAR_3: ''
VAR_4: 'file.txt'


Linux:

$ ./try.sh
sample.txt
1
2
sed: -e expression #1, char 27: Unmatched ) or \)
3
4
VAR_1: 'sample.txt'
VAR_2: ''
VAR_3: 'sample.txt'
VAR_4: 'sample.txt'
file.txt
1
2
sed: -e expression #1, char 27: Unmatched ) or \)
3
4
VAR_1: 'file.txt'
VAR_2: ''
VAR_3: ''
VAR_4: 'file.txt'


More testing:


ksh $ echo `echo '\\'`
\
ksh $ echo `echo "\\"`
"
ksh $ echo `echo "\\\"`
\



ksh $ echo $(echo '\\')
\
ksh $ echo $(echo "\\")
\
ksh $ echo $(echo "\\\")
>
> ^C



bash $ echo `echo '\\'`
\
bash $ echo `echo "\\"`
bash: command substitution: line 1: unexpected EOF while looking for matching `"'
bash: command substitution: line 2: syntax error: unexpected end of file

bash $ echo `echo "\\\"`
\



bash $ echo $(echo '\\')
\\
bash $ echo $(echo "\\")
\
bash $ echo $(echo "\\\")
>
>