LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Help with creating a shell script (https://www.linuxquestions.org/questions/programming-9/help-with-creating-a-shell-script-362692/)

windisch 09-12-2005 01:21 PM

Help with creating a shell script
 
I'm in the process of creating a request system for my shoutcast server (using sc_serv and sc_trans_linux). I have created the frontend using php and mysql to grab all of the data I need. On the backend I need to create a script to move around the playlist, and load the request file when someone creates it.

My plan is:
User requests the song and is placed into a request file.
I would like to have a file monitor the file and detect if anything is added (tail -f perhaps?)
Then I would need to see if the request file is already being played on the server.
If it is, just add the song to the end of the file and reload the playlist.
If not, load the request file.
After a song is queued, delete the file from the playlist.
If playlist is empty reload the default playlist.

My problem is, I'm not sure how to delete a line from a playlist, add to the end of a playlist and detect the presence of a file. If someone could give me a few hints, that would be great.

Thanks,
Adam Windisch

windisch 09-12-2005 01:49 PM

If someone just knows the command I should use, but not how to use it, let me know. I'm just not sure on how to start that part of the script.

infinity42 09-12-2005 02:17 PM

This script should give you some pointers (never used shoutcast so bear with me ;)):
What I have done is to have two files; request.txt & playlist.txt. Whenever a song is added to request.txt it is added to the end of playlist.txt. If the song is already in playlist.txt then it is deleted from playlist.txt before adding it to the end. I hacked this script up pretty quickly, so there is no sanity checks etc.
Code:

#!/bin/bash
PL_FILE='playlist.txt'
REQ_FILE='request.txt'
#Check if PL_FILE *doesn't* exists (without the bang (!) it would check if it did exist)
if [ ! -f $PL_FILE ];then
        #If it doesn't exist then create an empty file using touch
        touch $PL_FILE
fi
tail -f $REQ_FILE|while read request;do
        #Use awk to echo only the lines which *aren't* the requested file
        cat $PL_FILE|awk '! /^'$request'$/ {print $NF}'>$PL_FILE
        #Put the requested file on the end of the playlist
        echo $request>>$PL_FILE
done

(Piping into loops and using read is really useful)
Hope that gives you some help, if you need any more explaination/help post back && I'll do my best.

windisch 09-12-2005 02:43 PM

Thanks infinity. That looks like I can use this for part of my script. Anyone have a tip for me about removing a line from the playlist after seeing it played in a log file? Or checking to see if the file is now empty after deleting the song?

On a side note:
If anyone thinks my logic is incorrect on how I am creating this script, let me know.

carl.waldbieser 09-12-2005 09:29 PM

Quote:

Originally posted by windisch
Thanks infinity. That looks like I can use this for part of my script. Anyone have a tip for me about removing a line from the playlist after seeing it played in a log file? Or checking to see if the file is now empty after deleting the song?

On a side note:
If anyone thinks my logic is incorrect on how I am creating this script, let me know.

You could just pipe the whole list through grep -v to remove the line and redirect it to a temp file. Then copy the temp file over the orignial file and append (>>) the extracted line to the end.

infinity42 09-13-2005 06:55 AM

Quote:

Originally posted by carl.waldbieser
You could just pipe the whole list through grep -v to remove the line and redirect it to a temp file. Then copy the temp file over the orignial file and append (>> ) the extracted line to the end.
I used awk thusly:
Code:

cat $PL_FILE|awk '! /^'$request'$/ {print $NF}'>$PL_FILE
This will put all lines that aren't exactly $request back into $PL_FILE. Then you can do the append (echo whatever >> $PL_FILE).

Side note: Is it safe to redirect straight back into a file that you are piping in from? I've never had any problems doing it, but i've never tried it extensively

Quote:

Originally posted by windisch
Anyone have a tip for me about removing a line from the playlist after seeing it played in a log file? Or checking to see if the file is now empty after deleting the song?
Checking for an empty file is easy, i like to use 'wc'
Code:

if [ `wc -c $file|sed 's/ .*//'` -eq 0 ];then
    file_is_empty
else
    file_is_not_empty
fi

As for the log file removing thing, you can use tail -f to monitor the log file and then either grep -v or my awk meathod to remove it from the playlist.

Hope that helps.

windisch 09-13-2005 07:50 AM

Wow, that should get me started. Let me see what I can do with that. Thanks for your help guys.

windisch 09-13-2005 09:06 AM

I'm making some progress with the script, thanks for your help guys. I have a question about the removal of a song from the list using this code:

Code:

cat $PL_FILE|awk '! /^'$request'$/ {print $NF}'>$PL_FILE
I was planning on monitoring the log file for the song being played with tail -f. The log file looks like this:
<09/13/05@08:11:12> [MAIN] Title Updated
<09/13/05@08:14:24> [DECODE] Opened 09 - Leaving An Old Friend.mp3
<09/13/05@08:14:46> [MAIN] Title Updated

How do I get the info after the word Opened into the $request file so I can use your code? I'm new to parsing.

infinity42 09-13-2005 12:00 PM

Code:

sed 's/.*] Opened \(.*\)/\1/'
Will give you just the file name. So you could use something like this:
Code:

tail -f $LOG_FILE|while read line;do
    cmd=$(echo $line|sed 's/.*[\(.*\)].*/\1/')
    filename=$(echo $line|sed 's/.*] Opened \(.*\)/\1/')
    if [ $cmd = "DECODE" ];then
          cat $PL_FILE|awk '! /^'$filename'$/ {print $NF}'>$PL_FILE
    fi
done

Note that I have not tested the above code, I'm to lazy right now lol. So it may need a little debugging.

I have seperated off the command in the log file into $cmd so you can act on other commands if you want to.

Have fun..

windisch 09-13-2005 12:09 PM

Great! Thanks again Infinity. I'll see what I can do.

windisch 09-13-2005 02:36 PM

I tested your script and its working inplaces. I am getting this error though:

sed: -e expression #1, char 18: invalid reference \1 on `s' command's RHS
./request_test: line 25: [: =: unary operator expected

Which is referring to the line with $cmd = "DECODE"

Code:

tail -f $LOG_FILE|while read line;do
    cmd=$(echo $line|sed 's/.*[\(.*\)].*/\1/')
    filename=$(echo $line|sed 's/.*] Opened \(.*\)/\1/')
    if [ $cmd = "DECODE" ];then
          cat $PL_FILE|awk '! /^'$filename'$/ {print $NF}'>$PL_FILE
    fi

What do I need to do to fix this?

infinity42 09-13-2005 02:50 PM

Ah yes, oops. I forgot that you have to escape the [ and ] characters in regular expressions:
Code:

cmd=$(echo $line|sed 's/.*[\(.*\)].*/\1/')
Should be:
Code:

cmd=$(echo $line|sed 's/.*\[\(.*\)\].*/\1/')
and
Code:

filename=$(echo $line|sed 's/.*] Opened \(.*\)/\1/')
should be
Code:

filename=$(echo $line|sed 's/.*\] Opened \(.*\)/\1/')
Note the backslashes to escape the [ & ].
The second error is due to the fact that cmd was being set to an empty string, as the sed script failed. So bash saw
Code:

if [ = "DECODE" ]
and coughed. Now cmd should be being set correctly, so that shouldn't be a problem.

Hope that solves it!

windisch 09-13-2005 02:57 PM

I'm getting something different now:
Program Error:

awk: cmd. line:1: ! /^11
awk: cmd. line:1: ^ unterminated regexp
awk: cmd. line:1: ! /^13
awk: cmd. line:1: ^ unterminated regexp
awk: cmd. line:1: ! /^16
awk: cmd. line:1: ^ unterminated regexp
awk: cmd. line:1: ! /^Electronica
awk: cmd. line:1: ^ unterminated regexp

It's grabbing the first word. But the - might be throwing it off. Can I set it up to detect everything after Opened and end it with .mp3? There is no specific pattern to the file names outside of having .mp3 at the end.

<09/13/05@14:37:46> [MAIN] Title Updated
<09/13/05@14:41:40> [DECODE] Opened 11 - Troian Beauty.mp3
<09/13/05@14:42:03> [MAIN] Title Updated
<09/13/05@14:45:02> [DECODE] Opened 13 - The Brink Of Time.mp3
<09/13/05@14:45:24> [MAIN] Title Updated
<09/13/05@14:47:31> [DECODE] Opened 16 - One-Winged Angel.mp3
<09/13/05@14:47:53> [MAIN] Title Updated
<09/13/05@14:54:29> [MAIN] SIGWINCH; Next Song
<09/13/05@14:54:30> [DECODE] Opened Electronica - Der Ententanz (Dance Little Bird).mp3
<09/13/05@14:54:52> [MAIN] Title Updated

infinity42 09-13-2005 03:39 PM

I think the problem is that bash is trying to interpret the $filename after it is epanded. Try this:
Code:

awk '! /^'"$filename"'$/ {print $NF}'
rather than
Code:

awk '! /^'$filename'$/ {print $NF}'
Note double quotes around $filename

Hope that helps!

windisch 09-14-2005 07:26 AM

We're getting somewhere now. I am now seeing this on the screen:

Updated
Dance.mp3
Updated
Shop.mp3
Updated
Caboose.mp3
Updated
Zamfir.mp3
Updated

Corresponding to this in the log file:

<09/14/05@07:09:57> [MAIN] Title Updated
<09/14/05@07:13:27> [DECODE] Opened David Bowie - Let's Dance.mp3
<09/14/05@07:13:49> [MAIN] Title Updated
<09/14/05@07:17:24> [DECODE] Opened 23 - Mysterious Shop.mp3
<09/14/05@07:17:46> [MAIN] Title Updated
<09/14/05@07:18:23> [DECODE] Opened Sugar Ray - Lemonade and Brownies - 12 - Caboose.mp3
<09/14/05@07:18:46> [MAIN] Title Updated
<09/14/05@07:21:34> [DECODE] Opened Kill Bill - 14 - The Lonely Shepherd - Zamfir.mp3
<09/14/05@07:21:56> [MAIN] Title Updated

What do I need to do to get the rest of the file name to be copied? Do I need to be worried about it grabbing "Updated"?


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