LinuxQuestions.org
Go Job Hunting at the LQ Job Marketplace
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices

Reply
 
Search this Thread
Old 06-25-2008, 04:18 AM   #1
tredegar
Guru
 
Registered: May 2003
Location: London, UK
Distribution: Ubuntu 10.04, mostly
Posts: 6,007

Rep: Reputation: 366Reputation: 366Reputation: 366Reputation: 366
bash: "cut" and "case" help please


This has been driving me mad for 2 days now.

I am trying to automate the detection of a USB soundcard
Sometimes it is detected as card 0, sometimes as card 1.
I am writing a little script to restart alsa with the appropriate config file.
It looks like this, and is run as root

Code:
#!/bin/bash
cardnum=$(grep Bose /proc/asound/cards | cut -c 1)
case $cardnum in
"")     # No Bose
        cp /usr/share/alsa/alsa.conf.orig /usr/share/alsa/alsa.conf
        /etc/init.d/alsa-utils restart
        ;;
0)     # Bose is card 0
        cp /usr/share/alsa/alsa.conf.bose0 /usr/share/alsa/alsa.conf
        /etc/init.d/alsa-utils restart
        ;;
1)     # Bose is card 1
        cp /usr/share/alsa/alsa.conf.bose1 /usr/share/alsa/alsa.conf
        # Create link for dsp or realplay is confused
        rm /dev/dsp
        ln -sT  /dev/dsp1 /dev/dsp
        /etc/init.d/alsa-utils restart
        ;;
*)      echo ERROR in /etc/rc.local - soundcard number not known >> /var/log/messages
        ;;
esac
exit 0
But it doesn't work. I get "ERROR in rc.local - soundcard number not known"

This does work (Changes in red):

Code:
#!/bin/bash
cardnum=$(grep Bose /proc/asound/cards | cut -c 1)
case $cardnum in
"")     # No Bose
        cp /usr/share/alsa/alsa.conf.orig /usr/share/alsa/alsa.conf
        /etc/init.d/alsa-utils restart
        ;;
0*)     # Bose is card 0
        cp /usr/share/alsa/alsa.conf.bose0 /usr/share/alsa/alsa.conf
        /etc/init.d/alsa-utils restart
        ;;
1*)     # Bose is card 1
        cp /usr/share/alsa/alsa.conf.bose1 /usr/share/alsa/alsa.conf
        # Create link for dsp or realplay is confused
        rm /dev/dsp
        ln -sT  /dev/dsp1 /dev/dsp
        /etc/init.d/alsa-utils restart
        ;;
*)      echo ERROR in rc.local - soundcard number not known >> /var/log/messages
        ;;
esac
exit 0
So cardnum is not being set to "0" or "1" it is being set to a 2-or-more-character value (maybe the second character is a newline?) Why? Is there something wrong with my cut ? It makes no difference if I cut -c1 or cut -c 1 or cut -b1 or cut -b 1

[Yes, I know it's an ugly hack, and I should be using udev-rules, but ...]

Last edited by tredegar; 06-25-2008 at 04:22 AM. Reason: untidiness
 
Old 06-25-2008, 04:45 AM   #2
Mr. C.
Senior Member
 
Registered: Jun 2008
Posts: 2,529

Rep: Reputation: 59
Include the value of cardnum in your output for the *) case, surrounded by quotes. You can always look at it under od if it is unprintable:

mycmd | od -bc

Try this program, and you'll spot your error. Pass it an argument, like 0, 1, 2, or nothing at all:

Code:
#!/usr/bin/bash

cardnum=$(echo $* | cut -c 1)

case "$cardnum" in
"")     echo No Bose
        ;;
0)     echo is card 0
        ;;
1)     echo is card 1
        ;;
*)      echo ERROR in rc.local - soundcard number not known
        ;;
esac

Last edited by Mr. C.; 06-25-2008 at 04:59 AM.
 
Old 06-25-2008, 04:58 AM   #3
tredegar
Guru
 
Registered: May 2003
Location: London, UK
Distribution: Ubuntu 10.04, mostly
Posts: 6,007

Original Poster
Rep: Reputation: 366Reputation: 366Reputation: 366Reputation: 366
Thanks for your reply Mr.C (I was wondering if you or tinkster would jump in first )
od - how very useful (I am rusty with bash)
Code:
tred@p4:~$ grep Bose /proc/asound/cards | cut -c 1  | od -bc
0000000 061 012 040 012
          1  \n      \n
0000004
So, not just one newline but two and an extra space (Explains why using 0?) Code goes here didn't work, but 0*) Code goes here did.
Can you explain what is going on?
 
Old 06-25-2008, 04:59 AM   #4
Mr. C.
Senior Member
 
Registered: Jun 2008
Posts: 2,529

Rep: Reputation: 59
See my edit - i hit save too quickly.
 
Old 06-25-2008, 05:19 AM   #5
tredegar
Guru
 
Registered: May 2003
Location: London, UK
Distribution: Ubuntu 10.04, mostly
Posts: 6,007

Original Poster
Rep: Reputation: 366Reputation: 366Reputation: 366Reputation: 366
OK. Thanks for the edit.
Here we go:
Code:
tred@p4:~$ ./testcase
No Bose
tred@p4:~$ ./testcase 0
is card 0
tred@p4:~$ ./testcase 1
is card 1
tred@p4:~$ # I bet the next line doesn't work though
tred@p4:~$ ./testcase `grep Bose /proc/asound/cards | cut -c 1`
is card 1
tred@p4:~$ # It does!
tred@p4:~$
If I try to do cut twice, as in
Code:
tred@p4:~$  cardnum=$(grep Bose /proc/asound/cards | cut -c 1)
tred@p4:~$  echo $cardnum | cut -c 1 | od -bc
0000000 061 012
          1  \n
0000002
tred@p4:~$
It seems I am no better off. There is still a newline character there that I neither need nor want. I am just "not seeing it". Sorry
 
Old 06-25-2008, 05:20 AM   #6
Mr. C.
Senior Member
 
Registered: Jun 2008
Posts: 2,529

Rep: Reputation: 59
Look very, very, carefully at the difference between your case in... statement and mine.
 
Old 06-25-2008, 12:59 PM   #7
tredegar
Guru
 
Registered: May 2003
Location: London, UK
Distribution: Ubuntu 10.04, mostly
Posts: 6,007

Original Poster
Rep: Reputation: 366Reputation: 366Reputation: 366Reputation: 366
Sorry for the delay - had to go to work.
Thanks for the hint, but....

I have looked very, very carefully at your case in statement and compared it to mine.

Yours has quotes around $cardnum mine doesn't. But I did try a variety of quote combinations over the last couple of days (around the variable name, and around the bits before the ")" in the case statement) and got precisely nowhere.

If I haven't yet exhausted your patience, please take look at this, which I think illustrates my problem well:

Code:
tred@p4:~$ cat testcase
#!/bin/bash
rawline=$(grep Bose /proc/asound/cards)
echo '$rawline' is '"'$rawline'"'
cardnum=$(grep Bose /proc/asound/cards| cut -c 1)<--There is no trailing space on this line
# cardnum=$(echo $* | cut -c 1)
echo '$cardnum' is '"'$cardnum'"'
echo and this is what it really looks like when piped through od -bc
echo $cardnum| od -bc
echo Now we will test cardnum to see if it is '"'1'"'

case "$cardnum" in
"")     echo No Bose
        ;;
0)     echo is card 0
        ;;
1)     echo is card 1
        ;;
*)      echo ERROR in rc.local - soundcard number not known
        ;;
esac

tred@p4:~$ ./testcase
$rawline is "1 [Audio ]: USB-Audio - Bose USB Audio Bose Corporation Bose USB Audio at usb-0000:00:03.1-1, full speed"
$cardnum is "1 " <<-notice the extra space after the 1 and before the closing quote
and this is what it really looks like when piped through od -bc
0000000 061 012
          1  \n  <-- WTF? A space is now a newline, or maybe not
0000002
Now we will test cardnum to see if it is "1"
ERROR in rc.local - soundcard number not known
tred@p4:~$ #Grrrrrrr. Time to admit humiliating defeat. Back to LQ ...
How can cardnum be both a 1 and a 1-followed-by-a-space and a 1-followed-by-a-newline (but I think the /n in the output of od was put there by the echo command. So maybe cardnum is only being two things at once. (Panic: is bash quantum?)

The only time this script does as it should is when I unplug the speakers, and it correctly returns "No Bose".

I made it print out rawline for you in case you wanted to test this script for yourself.

I expect I'll be kicking myself soon, but I just do not understand what is going wrong.

Any ideas? I appreciate your input.

Last edited by tredegar; 06-25-2008 at 01:00 PM.
 
Old 06-25-2008, 02:14 PM   #8
Mr. C.
Senior Member
 
Registered: Jun 2008
Posts: 2,529

Rep: Reputation: 59
Something's not right here. I perform the same test, using a file with your contents, and your code. It runs as expected:

Code:
$ cat confused.sh 
#!/bin/bash

infile=/tmp/cards

rawline=$(grep Bose $infile)
echo '$rawline' is '"'$rawline'"'
cardnum=$(grep Bose $infile | cut -c 1) #--There is no trailing space on this line
# cardnum=$(echo $* | cut -c 1)
echo '$cardnum' is '"'$cardnum'"'
echo and this is what it really looks like when piped through od -bc
echo $cardnum| od -bc
echo Now we will test cardnum to see if it is '"'1'"'

case "$cardnum" in
"")     echo No Bose
        ;;
0)     echo is card 0
        ;;
1)     echo is card 1
        ;;
*)      echo ERROR in rc.local - soundcard number not known
        ;;
esac

$ ./confused.sh 
$rawline is "1 [Audio ]: USB-Audio - Bose USB Audio Bose Corporation Bose USB Audio at usb-0000:00:03.1-1, full speed"
$cardnum is "1"
and this is what it really looks like when piped through od -bc
0000000  061 012                                                        
           1  \n                                                        
0000002
Now we will test cardnum to see if it is "1"
is card 1
The newline you see is coming from echo itself; it is not contained in the variable. Use -n to prevent:

Code:
$ cardnum=$(grep Bose cards | cut -c 1)         
$ echo $cardnum | od -bc
0000000  061 012                                                        
           1  \n                                                        
0000002
$ echo -n $cardnum | od -bc
0000000  061                                                            
           1                                                            
0000001
Look at od -bc of your cards file.

Last edited by Mr. C.; 06-25-2008 at 02:18 PM.
 
Old 06-25-2008, 03:11 PM   #9
estabroo
Senior Member
 
Registered: Jun 2008
Distribution: debian, ubuntu, sidux
Posts: 1,094
Blog Entries: 2

Rep: Reputation: 111Reputation: 111
I don't know why you are getting the extra character in cut, but you could just use a substring operation in the shell to get that first character.

#!/bin/bash
rawline=$(grep Bose $infile)
cardnum=${rawline:0:1}

...
 
Old 06-25-2008, 04:35 PM   #10
Mr. C.
Senior Member
 
Registered: Jun 2008
Posts: 2,529

Rep: Reputation: 59
You're right estabroo, at some point you have to throw in the towel. But not too early!

Otherwise, we miss the opportunity to learn important concepts in an environment, such as newline->space translation during shell variable assignment, echo and the actual stream of bytes output (and how -e, -n affects), tools like od to examine the data, shell variable quoting (and how lack of quoting essentially alters the appearance of a language statement), etc. All good learning opportunities here.
 
Old 06-25-2008, 05:01 PM   #11
tredegar
Guru
 
Registered: May 2003
Location: London, UK
Distribution: Ubuntu 10.04, mostly
Posts: 6,007

Original Poster
Rep: Reputation: 366Reputation: 366Reputation: 366Reputation: 366
Thanks for your input estabroo.
I have an uneasy feeling that Mr.C knows the answer to my problem and he is quite properly trying to "lead the horse to water" but it (I) won't drink.

@Mr.C
Quote:
Something's not right here. I perform the same test, using a file with your contents, and your code. It runs as expected:
OK. But I am annoyed that you can run it and I cannot.

May I ask, what distro are you using? I am running kubuntu 6.06 on the PC I am having problems with. 6.06 is "Long Term Support", and up to date.

I'll try running these scripts on some other distros, when I can find time (=now + 1 week).
And I'll do an od -bc of my cards file (or more likely the output of grep Bose /proc/asound/cards because I am still not sure where the problem lies.
Until later, and thanks
 
Old 06-25-2008, 05:28 PM   #12
Mr. C.
Senior Member
 
Registered: Jun 2008
Posts: 2,529

Rep: Reputation: 59
Both NetBSD, and a hand-built 2.4-based linux box. But the important point would be the shell version. It is doing the work.

$ echo $BASH_VERSION
3.2.33(1)-release

$ echo $BASH_VERSION
3.2.1(1)-release


Add

Code:
echo LENGTH: ${#cardnum}
just after you assign cardnum to see its length. And, btw, trailing spaces after your command substitution in the assignment to cardnum would be ignored, so you don't have to worry about them. To include spaces, you'd need them protected by quotes.

Some other considerations - grep is *line* oriented, and lines require proper terminators. The main difference between your environment and mine is that you have the raw data from grep Bose /proc/asound/cards; I had to create a look-alike to test file. Get an od -bc of that /proc/asound/cards file.

Your results from:


Code:
tred@p4:~$ grep Bose /proc/asound/cards | cut -c 1  | od -bc
0000000 061 012 040 012
          1  \n      \n
0000004
are consistent with

Code:
tred@p4:~$  echo $cardnum | cut -c 1 | od -bc
0000000 061 012
          1  \n
0000002
because in the assignment to a shell variable (eg. cardnum), newlines and extra whitespace between successive lines is converted to a single space, and trailing whitespace is removed:
Code:
$ echo -ne '1\n \n' | od -bc 
0000000  061 012 040 012                                                
           1  \n      \n
0000004

$ cardnum=$(echo -ne '1\n \n')

$ echo  $cardnum | od -bc   
0000000  061 012                                                        
           1  \n                                                        
0000002
 
Old 06-26-2008, 02:08 PM   #13
tredegar
Guru
 
Registered: May 2003
Location: London, UK
Distribution: Ubuntu 10.04, mostly
Posts: 6,007

Original Poster
Rep: Reputation: 366Reputation: 366Reputation: 366Reputation: 366
I finally cracked it.
I was at work, so only able to play with linux on my laptop.
No USB speakers, but I could identify its single soundcard as 0 and the script worked.
So when I got home I copied it to my desktop, changed the grep from HDA-Intel to Bose and it didn't work.

Here's the moment of enlightenment, on my desktop:
Code:
tred@p4:~# cat /proc/asound/cards
0 [Audio          ]: USB-Audio - Bose USB Audio
                     Bose Corporation Bose USB Audio at usb-0000:00:03.1-1, full speed
1 [SI7012         ]: ICH - SiS SI7012
                     SiS SI7012 with AD1980 at 0xa400, irq 209
tred@p4:~# grep "Bose" /proc/asound/cards
0 [Audio          ]: USB-Audio - Bose USB Audio
                     Bose Corporation Bose USB Audio at usb-0000:00:03.1-1, full speed
tred@p4:~# grep "Bose" /proc/asound/cards | cut -c1
0
   <-- And here is an apparently blank line. It should not be there
tred@p4:~# grep "Bose" /proc/asound/cards | cut -c1 | od -bc
0000000 060 012 040 012
          0  \n      \n <-- a 0 then newline then space then newline. Bad
0000004
tred@p4:~#
tred@p4:~# grep ": USB-Audio" /proc/asound/cards | cut -c1 | od -bc
0000000 060 012
          0  \n   <--Much better
0000002
tred@p4:~#

So my error was not choosing a unique identifier for the line that begins with the soundcard number.
The grep "Bose" returned two lines (and I did not realise that the cut would work on both of those lines. Hence the incorrect cardnum not being allocated just "" "0" or "1"

So here is the (rc.local) script that finally works properly (until another unforseen situation crops up):

Code:
#!/bin/bash -e
#
# Simple control of Bose USB speakers
# If they are plugged in at boot, they'll be used,
# otherwise the internal soundcard will be used.
#
# It may fail if anything is using the sound card when it is called.
# Sometimes the Bose is allocated as card 1, sometimes as card 0
# So it gets a bit more complicated
# I wish I knew how to get udev to handle this (Homework required)

foo=$(grep ": USB-Audio" /proc/asound/cards | cut -c 1)

case $foo in

"")     # No Bose
        cp /usr/share/alsa/alsa.conf.orig /usr/share/alsa/alsa.conf
        /etc/init.d/alsa-utils restart
        ;;
0)      # Bose is card 0
        cp /usr/share/alsa/alsa.conf.bose0 /usr/share/alsa/alsa.conf
        /etc/init.d/alsa-utils restart
        ;;
1)      # Bose is card 1
        cp /usr/share/alsa/alsa.conf.bose1 /usr/share/alsa/alsa.conf
        # Create link for dsp or some apps are confused
        rm /dev/dsp
        ln -sT  /dev/dsp1 /dev/dsp
        /etc/init.d/alsa-utils restart
        ;;
*)      echo ERROR in rc.local - unknown soundcard number >> /var/log/messages
        ;;
esac
exit 0
Mr.C, thanks for your patience, suggestions, and especially for reminding me about od (very useful)

Now I can go off and add a correction to a previous post ( http://www.linuxquestions.org/questi...efault-649705/ ) about getting USB speakers recognised and auto-configured.

Last edited by tredegar; 06-27-2008 at 11:57 AM. Reason: Bad link-paste
 
Old 06-26-2008, 02:39 PM   #14
Mr. C.
Senior Member
 
Registered: Jun 2008
Posts: 2,529

Rep: Reputation: 59
Always verify your input data, and check your commands in small pieces before chaining long pipelines, esp. with pattern matching.

Change your grep to FORCE looking for a line that starts with a number. Always use as restrictive an RE match as necessary to reduce chances of other unexpected matches: Eg.:

grep '^[0-9].*USB-Audio' cards


Good job.
 
Old 06-26-2008, 04:31 PM   #15
tredegar
Guru
 
Registered: May 2003
Location: London, UK
Distribution: Ubuntu 10.04, mostly
Posts: 6,007

Original Poster
Rep: Reputation: 366Reputation: 366Reputation: 366Reputation: 366
Quote:
grep '^[0-9].*USB-Audio' cards
Ah! An altogether neater solution.
You have shown me something(s) useful for the future.
Thanks again
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
bash script: using "select" to show multi-word options? (like "option 1"/"o zidane_tribal Programming 6 03-21-2013 10:35 AM
Standard commands give "-bash: open: command not found" even in "su -" and "su root" mibo12 Linux - General 4 11-11-2007 10:18 PM
LXer: Displaying "MyComputer", "Trash", "Network Servers" Icons On A GNOME Desktop LXer Syndicated Linux News 0 04-02-2007 08:31 AM
bash-2.05b# Xlib: extension "XFree86-DRI" missing on display ":0.0". citrus Linux - General 8 02-22-2004 10:43 AM


All times are GMT -5. The time now is 04:38 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration