User Tools

Site Tools


tutorials:bash_scripting:part3

3. Creating a configuration file on the fly and stream editing


Someone on the list asked If I'd do something with stream editors. In this tutorial I'll use pipes, grep, sed and awk to help set a variable in a configuration file when I log into a session. Grep in this case will be used to print lines matching a given pattern to stdout. Sed will be used to print only one line piped from grep to stdout. Awk will be used to print just one field from the line piped in from sed.

Grep is a pattern matcher, sed is a non interactive editor that acts on streams piped into it and awk is actually a pattern matching programming language that is quite handy. Some of the things you can do with sed you can do with grep and some of the things you can do with awk you can do with sed and there are even other applications that could have been used but his is how I solved this problem.

Sound confusing? There are more ways than one to stream edit a cat.

I have a C-Media PCI sound card installed on my desktop box which also has on board sound via an NVidia chip.

I have disabled the NVIDIA chip in the BIOS. However, it is still listed in /proc/asound/cards and sometimes the order of listing changes. The NVIDIA card is listed first which results in no audio.

rick[~]$ cat /proc/asound/cards
 0 [NVidia         ]: HDA-Intel - HDA NVidia
                      HDA NVidia at 0xf4000000 irq 16
 1 [CMI8738        ]: CMI8738-MC6 - C-Media CMI8738
                      C-Media CMI8738 (model 55) at 0xa000, irq 16

I have a configuration file called ~/.asoundrc to provide settings required for recording off my sound card and I can also use it to set which sound device I want to use

rick[~]$ cat .asoundrc
defaults.ctl.card 1
defaults.pcm.card 1
defaults.timer.card 1

pcm.copy {
	type plug
	slave {
		pcm hw
	}
	route_policy copy
}

In order to have the correct sound card setting I will put together a script that runs when I start up a session. It will check the number of my sound card in /proc/asound/cards then re-write my ~/.asoundrc using the correct card number for my C-Media card.

The basic script will will create an ~/.asoundrc on the fly. The output of each echo command is redirected to the file ~/.asoundrc when the script runs.

#!/bin/bash

echo "defaults.ctl.card 1" > ~/.asoundrc
echo "defaults.pcm.card 1" >> ~/.asoundrc
echo "defaults.timer.card 1" >> ~/.asoundrc
echo -e "\npcm.copy {" >> ~/.asoundrc
echo "type plug" >> ~/.asoundrc
echo "    slave {" >> ~/.asoundrc
echo "          pcm hw" >> ~/.asoundrc
echo "          }" >> ~/.asoundrc
echo "    route_policy copy" >> ~/.asoundrc
echo "}" >> ~/.asoundrc

The first echo command uses a single “>”. This will truncate the existing ~/.asoundrc to zero length (read delete) before starting with a new line with the redirected stdout from echo.

All the other echo commands use “»” for redirection so that the stdout from those commands will be appended to the file.

There is one echo command that uses the “-e” flag so that a newline can be inserted in the file using the escape character “\n”

In order to change the card number I would have to edit the script by hand which is not much better than editing the file itself.

This is where stream editing comes in. I can use a variable for the card number and create the variable each time the script is run using the following:

cat /proc/asound/cards | grep CMI | sed q | awk -F " " '{ print $1 }'

The stdout from each command is piped to the next command until just the card number remains.

Cat is used to pipe the text of ~/.asoundrc to grep and grep is used to list just the lines relevant to the C-Media card.

bash-4.1$ cat /proc/asound/cards | grep CMI
 0 [CMI8738        ]: CMI8738-MC6 - C-Media CMI8738
                      C-Media CMI8738 (model 55) at 0xa000, irq 16

Grep outputs two lines and I use sed to print just the first line which provides the card number.

bash-4.1$ cat /proc/asound/cards | grep CMI | sed q
 0 [CMI8738        ]: CMI8738-MC6 - C-Media CMI8738

Awk is finally used to print (to stdout) the contents of the first field which in this case is 0.

bash-4.1$ cat /proc/asound/cards | grep CMI | sed q | awk -F " " '{ print $1 }'
0

Note that -F “ ” tells awk that the field separator is whitespace and '{ print $1 }' is used to print the first field (only) to stdout.

Here's the final script:

#!/bin/bash
# /usr/local/set-soundcard	rm20120529

card_no=`cat /proc/asound/cards | grep CMI | sed q | awk -F " " '{ print $1 }'`

echo "defaults.ctl.card $card_no" > ~/.asoundrc
echo "defaults.pcm.card $card_no" >> ~/.asoundrc
echo "defaults.timer.card $card_no" >> ~/.asoundrc
echo -e "\npcm.copy {" >> ~/.asoundrc
echo "type plug" >> ~/.asoundrc
echo "    slave {" >> ~/.asoundrc
echo "          pcm hw" >> ~/.asoundrc
echo "          }" >> ~/.asoundrc
echo "    route_policy copy" >> ~/.asoundrc
echo "}" >> ~/.asoundrc

# End of scipt

I use XFCE and to run this script each time I log in all I have to do is add the script to the list in Settings > Sessions and Startup > Application Autostart. You may have noted that this tutorial started with my C-Media card listed as the second card (1). Actually it was set as the first card (0) when I booted up this morning. After writing this script and setting XFCE to run it when I start a session, I logged out and then back in.

bash-4.1$ cat ~/.asoundrc
defaults.ctl.card 0
defaults.pcm.card 0
defaults.timer.card 0

pcm.copy {
type plug
    slave {
          pcm hw
          }
    route_policy copy
}

Cheers!

tutorials/bash_scripting/part3.txt · Last modified: 2017/10/12 21:58 by 127.0.0.1