LinuxQuestions.org
Share your knowledge at the LQ Wiki.
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 04-22-2010, 02:45 PM   #1
jakekatz
LQ Newbie
 
Registered: Sep 2009
Location: Ottawa, Ontario, Canada
Distribution: RHEL 7.x, Ubuntu 18.x
Posts: 5

Rep: Reputation: 0
Q: Dynamic Variables - How The Heck ?


Good day.

I'm writing what I thought was a VERY simple script to interface the cdrecord command which is too complicated for the average user.

I want the script to run the cdrecord --scanbus and present the user with a list of burners installed on his/her system. Many PC's have multiple drives install, thus the reason I need this script. This is only the first step in this script, more interaction will follow, but I just can't get past the first step. I want to scanbus, store device names in dynamic variables and present user with the description, not the cryptic 0,0,0 or 0,1,0 or 1,0,0 device addressing.


For this example, lets say the following produce this output on my particular system
Code:
$ cdrecord --scanbus 2>/dev/null | grep "[0-9],[0-9],[0-9]"
   0,0,0     0) 'LITE-ON ' 'LTR-52246S      ' '6S0D' Removable CD-ROM
   0,1,0     1) 'HL-DT-ST' 'DVD-ROM GDR-H30N' '1.00' Removable CD-ROM
   0,2,0     2) *
<snip>
   0,7,0     7) HOST ADAPTOR
So, what I want to do is capture the device "#,#,#" and the description, so the user can make an informed decision as to which device his blank CD is in.

I need to create dynamic variables, I though I knew how to do this, but for some reason they don't get exported outside of the while loop.

Here is Example that does NOT (err NOT) work:

The man script: cdmenu
Code:
#!/bin/bash
set -a
echo ""
echo "Choose a #number,  0 -> 6 to select your recording device..."
echo ""
c=0
# grep -v "*" on next line omits empty drive addr which are represented with the * symbol

cdrecord --scanbus 2>/dev/null | grep "[0-9],[0-9],[0-9]" | grep -v "*" | \
while read line; do
  a=`echo ${line} | awk '{print $1}'`
  b=`echo ${line} | awk '{print $2 " " $3 " " $4 " " $5}'`
  eval a_${c}=\`echo \"$a\"\`
  eval b_${c}=\`echo \"$b\"\`
  #eval echo \"Value of a_$c: \$a_$c\"
  #eval echo \"Value of b_$c: \$b_$c\"
  eval echo \" \#$c  --  \$b_$c\"
  let c="$c + 1"
done

# Okay, at this point, I'm assuming this is what I have in my dynamic,
# variables, your milage may vari as output differes from linux/UNIX
#
# a_1 = 0,0,0
# b_1 = 'LITE-ON ' 'LTR-52246S'
#
# a_2 = 0,1,0
# b_2 = 'HL-DT-ST' 'DVD-ROM GDR-H30N'
#
# This is proven by the two lines commented out in 
# the while loop
#
# Here's where I get totally stuck.
echo ""
read -p "Answer: " d
eval device=\`echo \"\$a_$d\"\`
eval description=\`echo \"\$b_$d\"\`

# debug uncomment
echo "Device value is: $device"
echo "Description value is: $description"
Results when run?
Code:
Choose a #number,  0 -> 6 to select your recording device...

 #0 -- 0) 'LITE-ON ' 'LTR-52246S
 #1 -- 1) 'HL-DT-ST' 'DVD-ROM GDR-H30N'
 #2 -- 7) HOST ADAPTOR

Answer:
I'll Answer 0 to choose the LITE-ON

Code:
Answer: 0
Device value is:
Description value is:
My answer should be: 0,0,0, but I get nada!

What am I doing wrong?

Any takers, I'm SURE it's some darn switch I'm forgetting to add for exporting beyond a while loop? I-dunno, my head hurts.

Thanks in advance!

J.
 
Old 04-22-2010, 06:53 PM   #2
chrism01
LQ Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Rocky 9.2
Posts: 18,355

Rep: Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751
Might I suggest you store the info in 1 or more arrays. That'll make it easier to retrieve the info by numbered index. Alternately, store the info in a temp file, 1 rec per line and store the matching index in an array.

Personally, if it was me, given you say there's more interactions etc to come, I'd do the whole thing in Perl. It's more powerful/better equipped to do this imho. YMMV
Not that it can't be done in bash.

Last edited by chrism01; 04-22-2010 at 06:58 PM.
 
Old 04-23-2010, 01:15 AM   #3
Kenhelm
Member
 
Registered: Mar 2008
Location: N. W. England
Distribution: Mandriva
Posts: 360

Rep: Reputation: 170Reputation: 170
The while loop is in a pipe and so is running in a subshell.
Variables set in a subshell are not available to the parent shell.
http://www.tldp.org/LDP/abs/html/process-sub.html
Look at Example 23-1. Code block redirection without forking
Code:
# Instead of the pipe to the while loop:
commands | while read line; do
 ...
done

# try process substitution:
while read line; do
 ...
done < <(commands)
 
Old 04-23-2010, 02:56 AM   #4
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
+1 to using arrays and not setting values in a pipeline.

Will this script be run with root privileges? cdrecord --scanbus does not work for an ordinary user on my system.
 
Old 04-23-2010, 07:03 AM   #5
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,005

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
Quote:
cdrecord --scanbus does not work for an ordinary user on my system.
Does on mine??

I do like the array idea but depending on what you want to show the user and whether or not you play with IFS
to get the right format???
I came up with an alternative but you will have to see what ya think:
Code:
#!/bin/bash

var=($(cdrecord --scanbus | awk 'NR > 1 && $3 !~ /\*/'))

select x in $(cdrecord --scanbus | awk 'NR > 1 && $3 !~ /\*/{gsub(/\47/,"");print $3}')
do
	echo $(cdrecord --scanbus | awk '$3 ~ /'"$x"'/{print $1}')
	break
done
 
Old 04-23-2010, 08:25 AM   #6
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
Or this
Code:
#!/bin/bash

i=-1
while read bus driver rest
do
    rest=${rest//\'/ }
    let i++
    array[i]="$bus $( echo ${rest%Removable CD-ROM*} )"  # The echo changes multiple spaces to single spaces
done < <(cdrecord --scanbus 2>&1 | grep 'Removable CD-ROM')

echo 'Choose a drive by number'
select drive in "${array[@]}"
do
    echo "You chose '$drive'"
done
EDIT: added redirection (in red) to keep things pretty

Last edited by catkin; 04-23-2010 at 08:28 AM. Reason: Added redirection (in red)
 
Old 04-23-2010, 08:47 AM   #7
jakekatz
LQ Newbie
 
Registered: Sep 2009
Location: Ottawa, Ontario, Canada
Distribution: RHEL 7.x, Ubuntu 18.x
Posts: 5

Original Poster
Rep: Reputation: 0
I thought that it was a subshell problem because variables were set in the loop, but not outside.

Thanks for the pointer to that article, cleared it up in a second!

Code:
#!/bin/bash
declare -a DEV
declare -a DES
index=0
while read line; do
  DEV[$index]=`echo ${line} | awk '{print $1}'`
  DES[$index]=`echo ${line} | awk '{print $2 " " $3 " " $4 " " $5}'`
  ((index++))
done < <(cdrecord --scanbus 2>/dev/null | grep "[0-9],[0-9],[0-9]" | grep -v "*")
read -p "Answer: " x
echo "DEV$x = ${DEV[$x]}"
echo "DES$x = ${DES[$x]}"
DEVICE=${DEV[$x]}
DESCRIPTION=${DES[$x]}
#etc...
Works great!


Quote:
Originally Posted by Kenhelm View Post
The while loop is in a pipe and so is running in a subshell.
Variables set in a subshell are not available to the parent shell.
http://www.tldp.org/LDP/abs/html/process-sub.html
Look at Example 23-1. Code block redirection without forking
Code:
# Instead of the pipe to the while loop:
commands | while read line; do
 ...
done

# try process substitution:
while read line; do
 ...
done < <(commands)
 
  


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: parse active process stderr, strip, dump into variables, use variables TimeFade Programming 1 02-13-2010 06:09 AM
Restricting Dynamic Ipaddress by based on Dynamic DNS host names karthik9110 Linux - Newbie 5 12-13-2009 11:46 PM
Dynamic / Auto-Updating Variables in BASH hackop Programming 1 04-25-2009 03:22 PM
"Dynamic" variables ganninu Linux - General 1 10-03-2006 11:52 AM
C++, when to go for static or dynamic variables? linuxlah Programming 21 02-05-2003 08:38 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 12:28 AM.

Main Menu
Advertisement
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
Open Source Consulting | Domain Registration