mersenneforum.org  

Go Back   mersenneforum.org > Great Internet Mersenne Prime Search > Software

Reply
 
Thread Tools
Old 2009-03-23, 18:40   #1
CRGreathouse
 
CRGreathouse's Avatar
 
Aug 2006

135338 Posts
Default Escape sequences in bash scripts?

I decided to teach myself shell scripting today*, but I got stuck writing my first script. The trouble spot: I don't know how to escape literals in quotes.

If I wanted to test if the first parameter was "dog", I could do this:
Code:
if [ "$1" = "dog" ]
then
  echo It's a dog!
else
  echo I have no idea what this is.
fi
But what if I wanted to test for 0x89? I tried "\211" and "\\211" (in case of double-escaping, which was a problem elsewhere in my script), but no such luck.

Here's the actual code, though it doesn't work properly:
Code:
head4=`head -c4 "$file"`
png="\\211PNG"
if [ "$head4" = "$png" ]
then
	gpicview "$file"
else
	echo File detection failed.  Initial part: $head4
	echo Expected: ........................... $png
fi
* I already know how to write Windows batch files and plenty of scripting languages like Perl, so this isn't as ambitious as it sounds. I'm just trying to get used to my new Linux computer -- first-time user and all that.
CRGreathouse is offline   Reply With Quote
Old 2009-03-23, 19:04   #2
akruppa
 
akruppa's Avatar
 
"Nancy"
Aug 2002
Alexandria

2,467 Posts
Default

The bash man page says you can create special characters with
$'string'
e.g,
PNG=$'\x89PNG'

Code:
PNG=$'\x89PNG'
head4=`head -c4 "fry.png"`
if [ "$head4" == "$PNG" ]; then echo 'Good news, everyone!'; fi
Good news, everyone!
This may be bash specific, using

PNG=`echo -e "\0211PNG"`

may be more portable. Or is -e a GNU extension again? Using printf (the command line program) instead may be more portable still.

Alex
akruppa is offline   Reply With Quote
Old 2009-03-23, 19:24   #3
CRGreathouse
 
CRGreathouse's Avatar
 
Aug 2006

135338 Posts
Default

Quote:
Originally Posted by akruppa View Post
This may be bash specific, using

PNG=`echo -e "\0211PNG"`

may be more portable. Or is -e a GNU extension again?
Great, that works. Thanks!
CRGreathouse is offline   Reply With Quote
Old 2009-03-23, 21:57   #4
CRGreathouse
 
CRGreathouse's Avatar
 
Aug 2006

3·1,993 Posts
Default

OK, here's another question. To avoid redundancy I'd like to collect the handling for each type of file together (whether detected by extension, header, or some other method). In a batch file I'd just do
Code:
REM There are actually lots of ways of writing this in batch...
IF "%1"=="help" GOTO Help
. . .
:Help
. . .
GOTO end
. . .
:end
but it looks like there's no goto here. At first it seemed simple: shell scripts support functions, so just make a function for each:
Code:
function Help {
. . .
}
. . .
if [ "$1" = "help" ]; then
  Help
. . .
but functions capture whatever I echo, and I haven't been able to properly redirect it. How is this usually handled?

Last fiddled with by CRGreathouse on 2009-03-23 at 21:58
CRGreathouse is offline   Reply With Quote
Old 2009-03-24, 10:46   #5
akruppa
 
akruppa's Avatar
 
"Nancy"
Aug 2002
Alexandria

2,467 Posts
Default

I'm not sure I understand "but functions capture whatever I echo"

For example
Code:
#!/bin/bash
function foo {
  echo "Hi, I'm function foo"
}

foo
outputs

./foo.sh
Hi, I'm function foo

Can you post the script that didn't output stuff like it should have? Or make a test case?

Alex
akruppa is offline   Reply With Quote
Old 2009-03-24, 15:13   #6
Kosmaj
 
Kosmaj's Avatar
 
Nov 2003

2×1,811 Posts
Default

If you want to detect the format of a file use the "file" command. It can detect many image formats, document types, etc.

If you want to learn bash, find a good tutorial and learn from examples. I can recommend you this one (in 3 parts).

Regarding escape sequences, avoid them, by converting binary data to strings (e.g., "od" command), and perform comparisons on them.

Last fiddled with by Kosmaj on 2009-03-24 at 15:24
Kosmaj is offline   Reply With Quote
Old 2009-03-24, 19:31   #7
CRGreathouse
 
CRGreathouse's Avatar
 
Aug 2006

3×1,993 Posts
Default

Quote:
Originally Posted by akruppa View Post
Can you post the script that didn't output stuff like it should have? Or make a test case?
It's not actually relevant anymore -- I redesigned the script -- but here's a testcase.
Code:
foo () {
	echo -n 'aa'
}
if [ `foo` = 'aa' ]; then
	echo Equal
else
	echo Unequal
fi
exit 0
It displays "Equal" instead of "aaUnequal".
CRGreathouse is offline   Reply With Quote
Old 2009-03-24, 19:43   #8
CRGreathouse
 
CRGreathouse's Avatar
 
Aug 2006

135338 Posts
Default

Quote:
Originally Posted by Kosmaj View Post
If you want to detect the format of a file use the "file" command. It can detect many image formats, document types, etc.
Ooh, thanks. That is more powerful (in almost all ways) than my script's detection routines: more file types, more information on the file, etc.

Quote:
Originally Posted by Kosmaj View Post
If you want to learn bash, find a good tutorial and learn from examples. I can recommend you this one (in 3 parts).
I've been reading http://tldp.org/LDP/abs/html/ and a bit of http://www.linuxtopia.org/online_boo...ripting_guide/ , but I'll look that one up as well. I think the learning process is going well (about 24 hours in); I have a working script I was able to set up in gedit. Now I only need one shortcut key for LaTeX, gcc, and such.

Quote:
Originally Posted by Kosmaj View Post
Regarding escape sequences, avoid them, by converting binary data to strings (e.g., "od" command), and perform comparisons on them.
Hmm, I'll have to play around with od a bit. Right now that part of my code is an ugly hack: I wasn't able to get the function to return values properly, and I never figured out why. This version works nicely when it does (requiring only [ ` ` ] around it, no -eq or the like) but I think it fails for sufficiently ugly input.
Code:
match () {
	# Does the $header start with the argument $1?  Useful when characters would
	# interfere with regexes.
	len=$((`echo "$1" | wc -c`-1))
	left=`echo "$header" | head -c"$len"`
	echo "\"$left\" = \"$1\""
}
. . .
header="`head -c999 "$file"`"
png=`echo -e '\0211PNG'`
MSOffice=`echo -e '\0320\0317\0021\0340\0241\0261\0032\0341'`
OOo=`echo -e '\0120\0113\0003\0004\0024\0000'`

if [ `match "$png"` ]; then
	exec_picture
elif [ `match "$OOo"` ]; then
	exec_OOo
I attached the whole script, learning piece/work-in-progress that it is, if you want context (or to critique!).
Attached Files
File Type: txt r.txt (7.5 KB, 181 views)

Last fiddled with by CRGreathouse on 2009-03-24 at 19:50
CRGreathouse is offline   Reply With Quote
Old 2009-03-24, 19:53   #9
akruppa
 
akruppa's Avatar
 
"Nancy"
Aug 2002
Alexandria

9A316 Posts
Default

The backticks `` make the output to stdout from the command between the backticks appear on the command line, so
foo=`echo -n Hi`
is equivalent to
foo="Hi"

In your case, the output "aa" from the foo function got substituted for `foo`, so the if-line reads
if [ "aa" = 'aa' ]; then

Normally a single "=" is assignment (without spaces around the "="!), you need a double "==" for comparison. Oddly, in your case the single = seems to do a comparison anyway...

The bash syntax can be pretty tricky, especially when variable expansion, quoting, globbing and whatnot are involved... an introductory text like Kosmaj posted would probably be worthwhile.

Alex
akruppa is offline   Reply With Quote
Old 2009-03-24, 20:16   #10
CRGreathouse
 
CRGreathouse's Avatar
 
Aug 2006

10111010110112 Posts
Default

Quote:
Originally Posted by akruppa View Post
In your case, the output "aa" from the foo function got substituted for `foo`, so the if-line reads
if [ "aa" = 'aa' ]; then
Right -- thus my use of the backtick feature in my match () function! For some reason the more obvious
Code:
if [ blah ]; then
  return 0
else
  return ''
fi
didn't work (I guess you're only supposed to return numbers?), and the
Code:
if [ blah ]; then
  return 0
else
  return 9
fi
with "if [ foo -eq 0 ]; then" also failed for some reason... thus my hack.
CRGreathouse is offline   Reply With Quote
Old 2009-03-25, 01:43   #11
Kosmaj
 
Kosmaj's Avatar
 
Nov 2003

2·1,811 Posts
Default

A few things;

1) To catch the return value from a function, refer to $? immidiately after calling it. Let's put your blah testing snippet in a funcion called "blahtest", then after

blahtest
ret=$?

you will have 0 or 9 in $ret. It's tricky, that's why it's better to use global varialbes to handle return values.

2) In bash you use single "=" to compare strings. That's why your code works. You can also use "==" but there is something tricky about it, it has different meaning in single brackets and in double brackets (will find you a reference later). It's the best to avoid it for the time being.

3) Binary valules in echo can confuse bash, that's why it's better to use "od" and do string comparisons. Even better, execute "file" and perform string comparisons on its output.
Kosmaj is offline   Reply With Quote
Reply

Thread Tools


Similar Threads
Thread Thread Starter Forum Replies Last Post
Scripts thread bsquared YAFU 4 2012-10-21 19:45
the scripts thread Mini-Geek Conjectures 'R Us 52 2012-05-29 21:43
aliquot escape firejuggler Aliquot Sequences 26 2012-01-19 08:15
High-altitude driver escape fivemack Aliquot Sequences 1 2011-04-24 09:34
DPGraph 2D/3D scripts nibble4bits Lounge 0 2008-01-16 17:05

All times are UTC. The time now is 09:41.


Sun Nov 28 09:41:18 UTC 2021 up 128 days, 4:10, 0 users, load averages: 0.86, 1.07, 1.05

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.

This forum has received and complied with 0 (zero) government requests for information.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation.
A copy of the license is included in the FAQ.