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 10-30-2006, 08:24 AM   #1
Fredde87
Member
 
Registered: Aug 2005
Posts: 158

Rep: Reputation: 30
Shell script variables


Hi

I have a script which might have some variables in it depending on what the user has chosen. The variables will be in in format $RemoveN, N being an even number (like $Remove2, $Remove4, $Remove 6 and so forth). they will equal Remove, and the N represents a line number in a file. I need to delete this line when N=Remove. So if $Remove4 is null, do nothing, but if $Remove6 eq Remove then delete line 6 from file /var/user/rules. Any simple way to do this? I could always go for the easy option and do a long list where he checks every variable at a time but I thought there must be a easier way to do it.
 
Old 10-30-2006, 09:21 AM   #2
unSpawn
Moderator
 
Registered: May 2001
Posts: 29,331
Blog Entries: 55

Rep: Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530
Code:
: ${Remove66=}
: ${Remove4=}
: ${Remove1=}
vars_set=${!Remove*}
 
Old 10-30-2006, 10:54 AM   #3
Fredde87
Member
 
Registered: Aug 2005
Posts: 158

Original Poster
Rep: Reputation: 30
Sorry I am fairley new to this. Could you give me a quick description to as what it does and how I can implement it?
 
Old 10-30-2006, 11:50 AM   #4
unSpawn
Moderator
 
Registered: May 2001
Posts: 29,331
Blog Entries: 55

Rep: Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530
Well, you just said you had the variable names and didn't talk about their values, so I had to make some (empty) variables to make it work as an example:
Code:
: ${Remove66=}
: ${Remove4=}
: ${Remove1=}
The "${!Remove*}" was a hint so you could:
Code:
for number in ${!Remove*}; do 
 echo "sed ${number//Remove/}d file \
 > file.tmp && mv file.tmp file"
done
I think you need a reverse sort though, else once you remove one line the other line numbers get skewed.
 
Old 10-30-2006, 12:15 PM   #5
Fredde87
Member
 
Registered: Aug 2005
Posts: 158

Original Poster
Rep: Reputation: 30
Thank you for your reply. I gave that an try but it just spat out a syntax error, bad substitution.
 
Old 10-30-2006, 01:12 PM   #6
unSpawn
Moderator
 
Registered: May 2001
Posts: 29,331
Blog Entries: 55

Rep: Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530
I gave that an try but it just spat out a syntax error, bad substitution.
Please dont *talk* about errors but *post* the exact one.
 
Old 10-31-2006, 04:25 AM   #7
Fredde87
Member
 
Registered: Aug 2005
Posts: 158

Original Poster
Rep: Reputation: 30
Sorry but that is the exact one, it says "Syntax Error: Bad substitution". My /bin/sh doesnt support substitution that is why. Is there anyother way to achive what I am looking to do?


Regards

Fredrik
 
Old 10-31-2006, 05:53 AM   #8
unSpawn
Moderator
 
Registered: May 2001
Posts: 29,331
Blog Entries: 55

Rep: Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530
Sorry but that is the exact one, it says "Syntax Error: Bad substitution". My /bin/sh doesnt support substitution that is why. Is there anyother way to achive what I am looking to do?
Are you saying you're using Bourne and not Bash?
Sure there will be another way.
Could you post a download location for the script?
 
Old 10-31-2006, 06:41 AM   #9
Fredde87
Member
 
Registered: Aug 2005
Posts: 158

Original Poster
Rep: Reputation: 30
I havent got a script yet... It is going to be a cgi script which gets directed to when the user presses a button (or perhaps if a user developes an application to delete several lines at once). This is what it looks like so far,
Code:
#!/bin/sh

QUERY_STRING=$(cat)
if [ -n "$QUERY_STRING" ]; then
  eval `query_string2sh "$QUERY_STRING"`
  # script goes here
fi
So nothing created yet. Here is the content of query_string2sh,

Code:
#!/bin/sh

[ $# -le 1 ] || { echo "Usage: $0 [query_string]" >&2; exit 2; }
qs=${1-"$QUERY_STRING"}

printf "%s\n" "$qs" \
| tr '&+' '\012 ' \
| sed -n 's/^\([A-Za-z_][A-Za-z0-9_]*\)=/\1 /p' \
| while read var value
  do value=`echo "$value" | sed "s/'/'\\\\\\''/g"`
    echo "PARAM_$var='$value'"
  done

So what query_strin2sh does is it will spit out eveything sent in the POST to its own variable, so if textfield=Test%20123 then there will be a variable called $PARAM_textfield with the value of "Test 123". Now this script I am creating now is for the remove button. There can be as many Remove buttons as the user wants (depends on how many lines there is in a config file). They are all called by the following serie, Remove2, Remove4, Remove6, Remove8, Remove10 and so forth. They will either not have a value att all (button not pressed) or string "Remove" (button is called Remove, so the label is sent as the value). Now if we have the following case scenario
PARAM_Remove2=
PARAM_Remove4=
PARAM_Remove6=
PARAM_Remove8=
PARAM_Remove10=Remove
PARAM_Remove12=
PARAM_Remove14=

The user has in this case pressed the fifth button which represents line 10. The script is then called and the text string Remove is put into $PARAM_Remove10. So now I need to delete lines 10 and 11 from file /var/temp

How do I do this? To summerise, I want to do the following but with a better solution
Code:
if [ $PARAM_Remove2 = Remove ]: then
  sed '2,3d' /var/temp > /var/temp2 && mv /var/temp2 /var/temp
fi
if [ $PARAM_Remove4 = Remove ]: then
  sed '4,5d' /var/temp > /var/temp2 && mv /var/temp2 /var/temp
fi
if [ $PARAM_Remove6 = Remove ]: then
  sed '6,7d' /var/temp > /var/temp2 && mv /var/temp2 /var/temp
fi
if [ $PARAM_Remove8 = Remove ]: then
  sed '8,9d' /var/temp > /var/temp2 && mv /var/temp2 /var/temp
fi
if [ $PARAM_Remove10 = Remove ]: then
  sed '10,11' /var/temp > /var/temp2 && mv /var/temp2 /var/temp
fi
if [ $PARAM_Remove12 = Remove ]: then
  sed '12,13d' /var/temp > /var/temp2 && mv /var/temp2 /var/temp
fi
if [ $PARAM_Remove14 = Remove ]: then
  sed '14,15d' /var/temp > /var/temp2 && mv /var/temp2 /var/temp
fi
if [ $PARAM_Remove16 = Remove ]: then
  sed '16,17d' /var/temp > /var/temp2 && mv /var/temp2 /var/temp
fi
But that looks so messy and it is hard to tell how many lines the user will have in that file...

Hope this clears things up.


Thanks

Last edited by Fredde87; 10-31-2006 at 06:55 AM.
 
Old 10-31-2006, 08:35 AM   #10
unSpawn
Moderator
 
Registered: May 2001
Posts: 29,331
Blog Entries: 55

Rep: Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530
Here's an idea. It's tested except for the sed part. It does use *Bash* though. Converting it to Bourne could be done (by you, not me). I wedged in some minimal checks and added TODO list items if you want to expand this. You should change FILE_NAME and FILE_TEMP_NAME locations and fill FILE_NAME with meaningful content for testing. If your webserver does not allow you to do file ops in the location you specify (good) then set up a Sudo Cmnd_Alias with NOPASSWD for it. No servicable user parts inside. Usability not implied nor functionality guaranteed. Store cold and dry. Do not drop. Keep away from children. Shell scripting addiction hazard warning.
YMMV(VM), as always ;-p

Code:
#!/bin/bash -  
# Purpose: Delete lines from FILE_NAME example.
# Args: none, expect QUERY_STRING
# Deps: Bash, GNU utils
# Run from: httpd as cgi
set -e
# Prepstage functions
PROGNAME=${0//*\//}
declare -r GOODCHARS="a-zA-Z0-9_&?="
FILE_NAME="/var/www/cgi-bin/test.dat"
FILE_TEMP_NAME="/var/www/cgi-bin/test.tmp"

# Access custom functions
function log() { # Log message, better not log QUERY_STRING
 /usr/bin/logger -i -p kern.err -t ${PROGNAME:="some unknown CGI"} "$@"
}

function checkChars() { # Check for allowed characters
 [ -n "${QUERY_STRING//[$GOODCHARS]/}" ] || \
 { echo "DENIED</title></head><body><h1>Illegal action.</h1>Try again.</body></html>"; exit 1; }
 # TODO: other checks should include:
 # - min length of QUERY_STRING
 # - max length of QUERY_STRING
 # - max elements in array QUERY_STRING
 # - existence of any LINENO= elements
 # - element format:
 #   - element[n]:0:6 equals "LINENO=", 
 #   - only numeric after equal sign
 # - last element is "Action=Remove+lines"
}

function insertForm() { # insert form in page
 local i; echo "<form name=\"Remove\">"; LINES=($(wc -l "${FILE_NAME}"))
 LINES=${LINES[0]}; for i in $(seq 1 ${LINES}); do
  echo "Remove line ${i}: <input TYPE=\"checkbox\" NAME=\"LINENO\" VALUE=\"${i}\" unchecked><br>"
 done;  echo "<input TYPE=\"submit\" NAME=\"Action\" VALUE=\"Remove lines\"></form>"
}

function removeRoutine() { # Change to using at, sudo or whatever.
 # TODO: parse exit value and return an understandable message.
 echo "sed ${i//LINENO=/}d ${FILE_NAME} > ${FILE_TEMP_NAME} \
 && mv -f ${FILE_TEMP_NAME} ${FILE_NAME}"
}

function queryAction() { # parse out returned string
 # TODO: this should have the array elements reversed.
 for i in ${QUERY_STRING//&/ }; do case "${i}" in LINENO=*) removeRoutine;; *) ;; esac
done
}

[ ! -e "${FILE_NAME}" ] && exit 127
[ -f "${FILE_TEMP_NAME}" ] && rm -f "${FILE_TEMP_NAME}"

# Bare minimum HTML header
echo -en "Content-type: text/html\n\n<html><head><title>\n"
checkChars
echo "Remove lines</title></head><body><pre>"
#echo "QS: ${QUERY_STRING//&/ }"
queryAction
echo "</pre>"
insertForm
echo "</body></html>"

exit 0
Have fun!

Last edited by unSpawn; 10-31-2006 at 08:37 AM.
 
Old 10-31-2006, 08:51 AM   #11
unSpawn
Moderator
 
Registered: May 2001
Posts: 29,331
Blog Entries: 55

Rep: Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530
Hmm. Come to think of it, you can slash the whole iteration thing if you can make queryAction return all and only numbers. Then you could make removeRoutine do sed '${number}d;${number}d;${number}d;' file.
 
Old 10-31-2006, 10:01 AM   #12
Fredde87
Member
 
Registered: Aug 2005
Posts: 158

Original Poster
Rep: Reputation: 30
Sorry you will have to excuse me, I am fairly new to this. Especially bash scripting, never written in bash, always sticked to bourne. I cant use any "${XXXX}" (If I understand that correctly what it does is check that the variable exists and that it is not null (unless it has semicolons in it).). Ill give it a play later today.


Edit: Got it to work! I had a hard time with getting your script to work though but your script pointed me in the right direction! Thank you very much! Switching to checkboxes and adding,
Code:
if [ $var = LINENO ]; then
      LINEN2=$(echo $value.$LINEN2)
      echo "PARAM_LINENO2='$LINEN2'"
    else
      echo "PARAM_$var='$value'"
    fi
to querystring2sh made my life very easy! So I now have the variable $PARAM_LINENO2 which contains the lines with a . as a delimiter, so it looks like this, "10.6.4.2."

Now I can easily do a for script to delete one line at a time. They are also reversed so that it starts the deletion at the back. Thank you so much for your help!

Last edited by Fredde87; 10-31-2006 at 10:48 AM.
 
Old 10-31-2006, 11:39 AM   #13
unSpawn
Moderator
 
Registered: May 2001
Posts: 29,331
Blog Entries: 55

Rep: Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530Reputation: 3530
Especially bash scripting, never written in bash, always sticked to bourne.
To me it seems a rather rare and valueable quality...

I can't see why you need to go through all sort of hoops with the querystring2sh? If you do enough tests on QUERY_STRING to make sure it's valid and sanitise (sed) unwanted parts you almost have your sed command.


So I now have the variable $PARAM_LINENO2 which contains the lines with a . as a delimiter, so it looks like this, "10.6.4.2."
If you can make $PARAM_LINENO2 read "10d;6d;4d;2d;" instead you already have your sed command and you can ditch the for loop.

Anyway. Good to see you got it working.
 
Old 11-01-2006, 04:35 AM   #14
Fredde87
Member
 
Registered: Aug 2005
Posts: 158

Original Poster
Rep: Reputation: 30
Never thought about that, might try that. Clean up some code. Thank you very much!

Last edited by Fredde87; 11-01-2006 at 06:06 AM.
 
  


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
shell script variables Gary_Menegon Programming 1 10-02-2006 10:28 AM
Using Variables in a Command that uses a Directory (Shell Script) CrimsonSkyZS Linux - General 4 01-11-2006 04:18 PM
Need help setting environment variables via shell script srosburg Linux - Newbie 2 12-08-2005 08:58 PM
Passing variables from AWK script to my shell script BigLarry Programming 1 06-12-2004 05:32 AM
Why?? can not use variables with shell script Bassam Linux - General 9 01-27-2004 08:42 AM


All times are GMT -5. The time now is 08:55 PM.

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
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration