Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

How can the white space character be escaped in printf for the purpose of this script that currently runs in a Cygwin client? The line containing the whitespace (which by itself works from the command line as echo $SPC) is

SPC=$(printf \\$(printf '%03o' 32))

In case you might wonder why, in this code I am trying to simulate an associative array such that it is not dependent on Bash 4+...would like this to be a generic example that theoretically can be run in virtually any bash environment.

Here is the entire script:

#!/bin/bash

DEFAULT_INDEX=""
LAST_INDEX=0
SPC=$(printf \\$(printf '%03o' 32))

# MICROSOFT OUTLOOK VERSIONS.
OUTLOOKS=( "Cancel^Do$SPCnot$SPCtry$SPCto$SPCsend$SPCmessage$SPCvia$SPCOutlook"
           "URL^Just$SPCthe$SPCmailto$SPCURL"
           "Outlook$SPC2003^C:\Program$SPCFiles\Microsoft$SPCOffice\Office12"
           "Outlook$SPC2007^C:\Program$SPCFiles\Microsoft$SPCOffice\Office12"
           "Outlook$SPC2010^C:\Program$SPCFiles\Microsoft$SPCOffice\Office14" )

# ITERATES THROUGH ARRAY AND MAKES NUMBERED SELECTION LIST.
printOutlooksArraySelectionList() {
    LIST_TITLE="MICROSOFT OUTLOOK SELECTION LIST"
    echo
    printf "\t\t\E[37;1;44m%-0s %s %s %s\033[0m" $LIST_TITLE
    echo
    echo
    DEFAULT_VALUE="Outlook 2010"
    index=0
    for i in "${OUTLOOKS[@]}"; do
        key=${i%%^*}
        value=${i##*^}
        if [ "$key" == "$DEFAULT_KEY" ]; then
            DEFAULT_INDEX=$index
    fi
            printf "\t\E[37;44m%-3s %-13s\033[0m \E[1;34;40m%-41s\033[0m\n" \
                   $index $key $value
            echo
            ((index++))
    done
    # SETS LAST_INDEX TO INDEX VALUE OF LAST ITEM IN ARRAY.
    ((LAST_INDEX = index - 1))
}

printOutlooksArraySelectionList

Would like the output to look like the following:

            MICROSOFT OUTLOOK SELECTION LIST

    0   Cancel        Do not try to send message via Outlook

    1   URL           Just the mailto URL

    2   Outlook 2003  C:\Program Files\Microsoft Office\Office12

    3   Outlook 2007  C:\Program Files\Microsoft Office\Office12

    4   Outlook 2010  C:\Program Files\Microsoft Office\Office14

To work-around, I ended up not using printf, but instead:

echo -e "\t\E[37;44m${index}\t${key}\033[0m\t\t\E[1;34;40m${value}\033[0m"

adequate for my purposes with this script.

share|improve this question
    
Try to show what do want to see. Is it leading spaces or zeros or what? –  ДМИТРИЙ МАЛИКОВ Nov 17 '11 at 21:05
    
Added the expected output to my question. Thank you. –  Mike Quentel Nov 17 '11 at 21:37
    
What are you expecting of $SPC value? It's ' ' now –  ДМИТРИЙ МАЛИКОВ Nov 17 '11 at 21:41
add comment

3 Answers 3

up vote 1 down vote accepted
  • Since you've already used quotes around the strings, using $SPC in them is not necessary and gives you no benefit. You don't need any definition of space there.

  • As Gilles pointed out, strings like "URL^Just$SPCthe$SPCmailto$SPCURL" contain non-existing variables. A variable ends either at a character that cannot be used in any variable name, or when it is (properly) delimiterred with {} as in ${key}.

share|improve this answer
    
Thank you, rozcietrzewiacz; your suggestion to put the SPC variable into ${SPC} solved the problem. –  Mike Quentel Nov 18 '11 at 12:46
    
Thanks for accepting, but you really should just get rid of the $SPC variable instead. It is useless - just put spaces in there. –  rozcietrzewiacz Nov 18 '11 at 13:03
    
When I just put spaces in the text, the script does not behave as expected in Cygwin. The script works without the SPC variable (as you suggest getting rid of $SPC) in a true Linux environment like Ubuntu 11.04 (just tested it in that environment). However, have not gotten it to work in Cygwin on Windows XP. –  Mike Quentel Nov 18 '11 at 15:46
    
This sounds very strange - you might want to investigate this further (use a simplest script possible). There might be some other error that causes this. –  rozcietrzewiacz Nov 18 '11 at 15:50
    
After further investigation, I think there is indeed something else that was causing the error in Cygwin. I again tested using just " " (no SPC variable) in the script, in Cygwin, and now it works. Could be something about my workstation configuration or some other factor. Weird. Again, thank you for pointing out the variable expansion aspect, in general. –  Mike Quentel Nov 18 '11 at 16:18
show 2 more comments

I don't understand what you're trying to do. Your code does set SPC to a string of length 1 whose single character is a space. This is a highly convoluted way of doing it: SPC=" " would work just as well and be comprehensible.

I haven't reviewed your whole script, but I do see something wrong later down: you write things like "URL^Just$SPCthe$SPCmailto$SPCURL". This produces the string URL^Just, because the variables $SPCthe, $SPCmailto and $SPCURL are not defined. When a variable expansion is immediately followed by a character that could be part of the variable name, you need to indicate the end of the variable name, for example by putting the name into braces: URL^Just${SPC}the${SPC}mailto${SPC}URL. I don't understand why you're not writing "URL^Just the mailto URL", though.

For your encoding of small hash tables, I suggest using two array, once for keys and one for values. That way, you can store arbitrary strings, without fearing encoding issues. Here's a sketch of what lookup and addition can look like (taking the names of the keys and values arrays as parameters is left as an exercise):

lookup () { # $1=key; set value to the value found
  for ((i=1; i<=${#keys}; i++)); do
    if [[ ${keys[$i]} = $1 ]]; then value=${values[$i]}; return 0; fi
  done
  unset value; return 1
}
add () { # $1=key $2=value
  for ((i=1; i<=${#keys}; i++)); do
    if [[ ${keys[$i]} = $1 ]]; then values[$i]=$2; return; fi
  done
  keys[$i]=$1; values[$i]=$2
}

A more efficient method would be to store each entry in a shell variable. For example, if the table foo maps somekey to somevalue, then set the variable table_foo_somekey=somevalue. You need to encode the keys into alphanumerics, which is non-trivial (one method is to hash the keys, e.g. with sha1, and store the key in table_foo_${sha1_of_somekey}_key and the value in table_foo_${sha1_of_somekey}_key). If you need to enumerate the keys in a table, you need to store the list separately.

Or, when you need things that go beyond the capabilities of a simple shell, you could reach for a more powerful tool. Ksh93 (not pdksh), bash 4 and zsh all have associative arrays. Beyond that, there's Perl and Python and the rest of them.

share|improve this answer
    
Thank you for the comments, suggestions, and information...I changed the assignment: SPC=" " but the result is still not as expected. Initially, I tried the '"URL^Just the mailto URL"' syntax, but it does not work as expected in Cygwin, hence the attempts at using escape characters that represent the whitespace character. –  Mike Quentel Nov 18 '11 at 4:55
1  
But what are you expecting from SPC? –  ДМИТРИЙ МАЛИКОВ Nov 18 '11 at 6:52
1  
@MikeQuentel I guarantee you that your SPC variable will not help with whatever problem you're having. The space character is not different on Cygwin. Remove it, which will fix some of the problems with your script as I've explained. Then, if you still need help, post your updated, simplified script, and explain what the script does, what you expect from the script, and how they differ. –  Gilles Nov 18 '11 at 8:11
add comment

I've already mentioned some misunderstanding of that problem. But anyway.

The line containing the whitespace (which by itself works from the command line as echo $SPC) is

SPC=$(printf \\$(printf '%03o' 32))

Actually, that line do not containing any whitespaces. It expands in

printf \\040

which expands in nothing good. And printfing a printf output is a really bad idea at all.

Print could show space symbols if you want it:

$> printf '  %03o\n' 32
  040

Leading nulls and leading zeros too:

$> printf "%010o\n" 32
0000000040

$> printf "% 10o\n" 32
        40

UPD by comment:

$> printf '\\%03o\n' 32
\040
share|improve this answer
    
Thank you for the clarification. Similarly, I had previously tried using the value of printf "\040" (octal value) which works at the command line by itself, but using the octal does not work with the script. –  Mike Quentel Nov 17 '11 at 21:53
    
The line SPC=$(printf \\$(printf '%03o' 32)) does set SPC to a single space character, in a highly convoluted way. While I agree with your “bad idea” characterisation, this bit does work as (possibly) intended. –  Gilles Nov 18 '11 at 10:37
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.