||03-12-2008 12:30 AM
kkpal, your solution will work, but it is inefficient - it invokes 8 external processes. Of course most of the time, performance is not an issue, else the programmer would not be using shell script, but even so, it's a good idea to try to reduce the number of external processes which are invoked.
A slightly less readable, but more efficient way to do it:
eval $(sed -e '1s/^/name=/' -e '2s/^/type=/' -e '3s/^/loc=/' -e '4s/^/snum=/' test.txt)
To understand what is going on, you might run this command from the prompt:
sed -e '1s/^/name=/' -e '2s/^/type=/' -e '3s/^/loc=/' -e '4s/^/snum=/' test.txt
...which will output this:
just takes this output as a string and executes it in the current shell. There are a few implications of this:
- For real world applications, you must be very careful what is in the data. Say this data comes from a web form... Some attacker might put shell commands web form and be able to have your program execute them! Imagine some malicious command like destroying your files, or worse, downloading and installing a root kit. An attacker might inser it by having a specially crafted name field, like this:
Generally speaking you should not eval data coming from outside your code unless you are take a lot of care to prevent this sort of thing. The same applies when you are taking external data and using it to build SQL statements.
evil$(evil command here)haxor
- Imagine one of the lines in the file containing a space. Say the name (first line) is "Matthew Gates". In your eval'd code this will end up as:
This is no good - if you want to assign the whole string including the space and everything after it, you must quote the data. This can afford some protection from embedded code attacks too, but you must not leave the attacker the option to prematurely end your quote. For example, the sed command might become:
Here we add three new sed commands. The first one removes existing quotes from the input data, the second and third add single quotes to the beginning and end of all lines. Now the assignment of the first line looks like this:
sed -e "s/'//g" -e "s/^/'/" -e "s/$/'/" -e '1s/^/name=/' -e '2s/^/type=/' -e '3s/^/loc=/' -e '4s/^/snum=/' test.txt