![]() |
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[/code] 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[/code] * 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. |
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! [/CODE] 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 |
[QUOTE=akruppa;166405]This may be bash specific, using
PNG=`echo -e "\0211PNG"` may be more portable. Or is -e a GNU extension again?[/QUOTE] Great, that works. Thanks! |
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[/code] 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 . . .[/code] but functions capture whatever I echo, and I haven't been able to properly redirect it. How is this usually handled? |
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 [/CODE] 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 |
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 [URL="http://www.ibm.com/developerworks/library/l-bash.html"]this one[/URL] (in 3 parts). Regarding escape sequences, avoid them, by converting binary data to strings (e.g., "od" command), and perform comparisons on them. |
[QUOTE=akruppa;166474]Can you post the script that didn't output stuff like it should have? Or make a test case?[/QUOTE]
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[/code] It displays "Equal" instead of "aaUnequal". |
1 Attachment(s)
[QUOTE=Kosmaj;166504]If you want to detect the format of a file use the "file" command. It can detect many image formats, document types, etc.[/QUOTE]
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=Kosmaj;166504]If you want to learn bash, find a good tutorial and learn from examples. I can recommend you [URL="http://www.ibm.com/developerworks/library/l-bash.html"]this one[/URL] (in 3 parts).[/QUOTE] I've been reading [url]http://tldp.org/LDP/abs/html/[/url] and a bit of [url]http://www.linuxtopia.org/online_books/advanced_bash_scripting_guide/[/url] , 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. :smile: [QUOTE=Kosmaj;166504]Regarding escape sequences, avoid them, by converting binary data to strings (e.g., "od" command), and perform comparisons on them.[/QUOTE] 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[/code] I attached the whole script, learning piece/work-in-progress that it is, if you want context (or to critique!). |
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 |
[QUOTE=akruppa;166556]In your case, the output "aa" from the foo function got substituted for `foo`, so the if-line reads
if [ "aa" = 'aa' ]; then[/QUOTE] 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[/code] didn't work (I guess you're only supposed to return numbers?), and the [code]if [ blah ]; then return 0 else return 9 fi[/code] with "if [ foo -eq 0 ]; then" also failed for some reason... thus my hack. |
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. |
| All times are UTC. The time now is 09:34. |
Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.