Showing posts with label bash. Show all posts
Showing posts with label bash. Show all posts

Monday, February 15, 2016

JSON grep

I haven't really done anything worth showing here for a while, but I've been playing around with Groovy recently, and it's hard not to do something weird and hack-y in Groovy, so here it is.

The problem was pretty basic. I had JSON configuration files for a benchmark and wanted to retrieve particular properties from JSON files to use them in bash scripts. Since the benchmark was done in Groovy, so I looked into a solution using Groovy as well. Finding the property in JSON is a little problematic, since the format is pretty complex, but Groovy (and most other languages, I suppose) can parse JSON files and dynamically create a data structure consisting of lists and maps, which then can be used using standard Groovy collection magic.

Once that structure is in place the only problem is to execute a Groovy command in bash on that data structure. I do this by creating a binding object, which represents an execution environment. I set a variable in the binding: the variable is called cfg and it is the entire data structure that I got by parsing JSON. Then I pass the binding to a Groovy shell object. The shell can execute any groovy command passed as string. Since it has access the binding with cfg defined, the Groovy commands can be executed using cfg. Then, Groovy code passed by argument to the script can be used to extract a particular item from the JSON file and print it. In addition, all those cool Groovy collection methods like grep, collect and inject can be used. The result of execution is simply printed on screen.

For my own convenience, since I want this script for executing things on the JSON data structure only, and I don't necessarily want to remember down the line that the variable inside the script is called cfg, I make the command I get via the argument always execute as a method of cfg. This is a bit arbitrary, and I can see that for some purposes this should be simplified and the user of the script should be made to remember herself to use cfg as appropriate, but, as I say, this is for my convenience as is.

An example usage is as follows:

groovy jsongrep.groovy -f file.json coordinator.host coordinator.port

This example is fairly straightforward. It assumes that the top level of the data structure is a map. We execute two command on it. The first one grabs the contents of data structure under coordinator from the top level structure and, again assuming that that is a map, grabs the contents under host. The second command grabs port from the latter. Traversing the structure using Groovy notation is fairly elegant, if I say so myself.

groovy jsongrep.groovy -f file.json 'hosts.inject(""){acc, e -> acc + " " + e}'

This example also assumes that the top level is a map. From this map we grab the substructure under the key hosts and execute inject on it. This is a fold-type function which accumulates the result of operations performed on individual elements of the collection. We use it to glom together a space-separated string. Not as elegant as the basic usage, I suppose, but it gives access to a very powerful mechanism, since you can do a lot of things using those Groovy collection methods.

The code:

 1 #!/usr/bin/env groovy
 2 
 3 import groovy.json.JsonOutput;
 4 import groovy.json.JsonSlurper
 5 
 6 def parser = new CliBuilder(usage: 'jsongrep.groovy [ -f FILE ] EXPRESSION [ EXPRESSION [...] ]')
 7 parser.with {
 8     f longOpt: 'file', args: 1, 'Path of JSON file.'
 9     h longOpt: 'help', args: 1, 'Usage information.'
10 }
11 
12 def options = parser.parse(args)
13 if (options.h) {
14     parser.usage()
15     return
16 }
17 
18 def path = options.f ? options.f : null
19 
20 def arguments = options.arguments()
21 def cfg = new JsonSlurper().parseText(path == null ? System.in.text : new File(path).text)
22 
23 Binding binding = new Binding()
24 binding.setVariable("cfg", cfg)
25 GroovyShell shell = new GroovyShell(binding)
26 
27 arguments.each { println (shell.evaluate ("cfg.$it")) }

The code is available on GitHub at groovy/jsongrep.groovy.

Thursday, March 18, 2010

PDF shorthand


There are periods of time when I have to do a lot of article editing or book writing, and I usually do that in LaTeX. I find that writing dockets in LaTeX helps me focus on the content, maintain coherent style throughout the document, and produce better-looking results... and I lost my patience with office suites in general.

There is however, one thing that annoys me. Since I tend to just use a text editor (vim, or kate, or gedit) I usually need to go into terminal and type in the four commands to compile the document into a pdf:

pdflatex meh.tex && \
bibtex meh && \
pdflatex meh.tex && \
pdflatex meh.tex

And since I'm kinda compulsive I do that kind of often. And when it's not in the history of commands (because e.g., I'd been writing a script during a break in editing) I get annoyed.

So I figured I could do a simple script that would take care of those commands. A simple script that just takes the name of the tex file and returns a pdf. And I did just that.

And then I started fiddling with it and adding silly features: making it quiet, interactive, whatever; and then a getopt interface on top of it all. So it got kind of convoluted by the end. Feature-wise it probably lays smack in the middle between lightweight and feature-rich. I.e., it is slightly too complex but doesn't have the feature you want.

But I still like it.

If you're looking for fun stuff, the usage function is interesting, even if I say so myself. Instead of writing out a sequence of echo commands explaining what the program does, I decided to use the comments I write on the top of the scripts always. So the usage command finds and parses the script file, and then, using awk yanks the large comment, strips it of the hash character in front, and prints it out to the user. It saved time, and I should remember to sue it in the future in this context.

Some examples of usage now. First, make pdf from tex, bibliography and all:

pdfshorthand top.tex

To make it not produce all those pesky temporary documents (ask before removing each file or not):

pdfshorthand -c top.tex
pdfshorthand -cf top.tex

And if you have no bibliography in your docket, you need to use the b flag:

pdfshorthand -b top.tex
pdfshorthand -bc top.tex
pdfshorthand -bcf top.tex

The code:
 
1 #!/bin/bash
2 #
3 # My shorthand for pdflatex
4 #
5 # Because I'm sick and tired of always putting in the same command over and
6 # over again just to compile a file into a PDF. This script does it for me.
7 # It's basically the equivalent for writing:
8 # pdflatex top.tex && bibtex top && pdflatex top.tex && pdflatex top.tex and
9 # then cursing because I'd have much preferred it to halt on error but that is
10 # way too much writing.
11 #
12 # Usage:
13 # shorthand [OPTION ...] FILE [FILE ...]
14 #
15 # The FILE can but doesn't have to end with the extension 'tex'. If it isn't,
16 # one will be added before passing the file to pdflatex; if it is, it will be
17 # removed before passing the file to bibtex.
18 #
19 # Options:
20 # -n|--no-colors Do not use colors in output. Normally, colors are used
21 # for key messages: on success, on failure, and when
22 # compilation starts.
23 #
24 # -b|--no-biblio Do not attempt to generate a bibliography using bibtex.
25 #
26 # -i|--interactive Run pdflatex in interactive mode (halt on error).
27 # Otherwise the compilation is run in non-stop mode.
28 #
29 # -q|--quiet Do not show any output from the command whatsoever.
30 # Else, compilation produces a lot of output (be advised).
31 #
32 # -c|--clean-up Clean up after the compilation - remove aux, blg, bbl,
33 # and log files from the working directory. The files will
34 # be backed up in /tmp/ec.XXX/ just in case though, and
35 # you will be asked before the actual removal of each file
36 # takes place.
37 #
38 # -f|--force When used with -c or --clean-up, the script will not ask
39 # before removing each temporary file from the working
40 # directory.
41 #
42 # -h|--help Print usage information.
43 #
44 # --latex-command Specify a command to run instead of pdflatex. It will be
45 # given some arguments that pdflatex would have been given
46 # i.e., -interaction MODE and -non-stop-mode.
47 #
48 # --bibtex-command Specify a command to run instead of bibtex.
49 #
50 # Example:
51 # shorthand top.tex
52 #
53 # Requires:
54 # pdflatex
55 # bibtex
56 #
57 # Author:
58 # Konrad Siek <konrad.siek@gmail.com>
59 #
60 # License:
61 # Copyright 2010 Konrad Siek
62 #
63 # This program is free software: you can redistribute it and/or modify it
64 # under the terms of the GNU General Public License as published by the Free
65 # Software Foundation, either version 3 of the License, or (at your option)
66 # any later version. See <http://www.gnu.org/licenses/> for details.
67 #
68
69 texcommand=pdflatex # name or path to command
70 bibcommand=bibtex # name or path to command
71 quiet=$false # true or $false
72 interactive=$false # true or $false
73 colors=true # true or $false
74 cleanup=$false # true or $false
75 force=$false # true or $false
76 no_biblio=$false # true or $false
77
78 # Print usage information.
79 usage () {
80 gawk '/^#/ && NR>1 {sub(/^#[ \t]?/,""); print; next} NR>1 {exit}' "$0"
81 }
82
83 # Print stuff to standard error.
84 stderr() {
85 echo $@ &> 2
86 }
87
88 # Parse options.
89 options=$(\
90 getopt \
91 -o ciqnhfb \
92 --long clean-up,interactive,quiet,latex-command:,bibtex-command:,no-colors,force,help,no-biblio \
93 -n $0 -- "$@" \
94 )
95
96 # Stop if there's some sort of problem.
97 if [ $? != 0 ]
98 then
99 [ $quiet ] && syserr "Argh! Parsing went pear-shaped!"
100 exit 1
101 fi
102
103 # Set the parsed command options and work with the settings.
104 eval set -- "$options"
105 while true
106 do
107 case "$1" in
108 --latex-command) texcommand="$2"; shift 2;;
109 --bibtex-command) bibcommand="$2"; shift 2;;
110 -c|--clean-up) cleanup=true; shift;;
111 -n|--no-colors) colors=$false; shift;;
112 -f|--force) force=true; shift;;
113 -i|--interactive) interactive=true; shift;;
114 -q|--quiet) quiet=true; shift;;
115 -h|--help) usage; exit 1;;
116 -b|--no-biblio) no_biblio=true; shift;;
117 --) shift; break;;
118 *) syserr "Ack! She cannae take it anymore, captain!"; exit 3;;
119 esac
120 done
121
122 # Various messages printed out by the script.
123 SUCCESS="Huzzah!"
124 FAIL="Your shipment of fail has arrived."
125 PROCESSING="Processing file <{}>"
126
127 # If no params given, print usage and quit with an error.
128 [ $# -lt '1' ] && (usage; exit 1)
129
130 # Specify the params for pdflatex for whatever level of interactiveness the
131 # user expects. We do this beforehand.
132 if [ $interactive ]
133 then
134 iparams="-interaction errorstopmode -halt-on-error"
135 else
136 iparams="-interaction nonstopmode"
137 fi
138
139 clean_up () {
140 if [ $cleanup ]
141 then
142 dir=`mktemp --tmpdir -d "$1.XXX"` && \
143 for ext in bbl blg log aux out nav snm
144 do
145 f="$1.$ext"; cp -v "$f" "$dir/$f"
146 if [ -f "$f" ]
147 then
148 [ $force ] && rm -vf "$f" || rm -vi "$f"
149 else
150 "Omitting file: $f"
151 fi
152 done
153 cp -v "$1.tex" "$dir/"
154 fi
155 }
156
157 # If the user wants colors, the messages can be prepared beforehand.
158 if [ $colors ]
159 then
160 # Add coloring control characters to the message strings:
161 # success, green; fail, red; processing, white; all bold.
162 SUCCESS="\033[32m\033[1m$SUCCESS\033[m"
163 FAIL="\033[31m\033[1m$FAIL\033[m"
164 PROCESSING="\033[37m\033[1m$PROCESSING\033[m"
165 fi
166
167 # If bibtex is not supposed to be run at all, run the 'true' command instead.
168 # The 'true' command will take whatever parameters and do absolutely nothing,
169 # then it'll report a success. So it fits perfectly with the other commands.
170 if [ $no_biblio ]
171 then
172 bibcommand=true
173 fi
174
175 # The shorthand method for the pdflatex/bibtex combination.
176 shorthand () {
177 # Cut off the extension, if any to create the bibtex argument,
178 dir=`dirname "$1"`
179 base=`basename "$1" .tex`
180 stump="$dir/$base"
181
182 # And now stick the extension back on to create the pdflatex argument.
183 full="$stump.tex"
184
185 # Print out what file is being processed.
186 echo -e ${PROCESSING//\{\}/$full}
187
188 # The pipe, where all the magic happens:
189 $texcommand $iparams "$full" && \
190 $bibcommand "$stump" && \
191 $texcommand $iparams "$full" && \
192 $texcommand $iparams "$full" && \
193 (clean_up "$base"; echo -e $SUCCESS) || echo -e $FAIL
194
195 # Finally print out an information whether the processing was a success or
196 # a failure.
197 }
198
199 # Do the thing.
200 for arg
201 do
202 # If quiet mode is on, send all results to the black hole.
203 [ $quiet ] && shorthand "$arg" 1> /dev/null 2>/dev/null || shorthand "$arg"
204 done


The code is also available at GitHub as bash/pdfshorthand.

Tuesday, February 23, 2010

Rotate video

No weird title for this one. No, this one was 100% purely itch-scratch oriented, and written in under under two hours.

Problem: I've been bowling and I made some short movies with my cell phone, but I recorded them horizontally instead of vertically. I basicaly forgot that, unlike with pictures, when you watch the movie you can't just press the rotation arrow in the movie player to turn it vertical or whatever.

Thus, a little zenity-enabled script around mencoder to convert these ineptly taken movies.

The code:
 
1 #!/bin/bash
2 #
3 # Rotate video
4 #
5 # A short and handy way to rotate videos, one file at a time (sorry).
6 #
7 # Usage:
8 # rotate_video [INPUT [OUTPUT [ROTATION]]]
9 #
10 # (If no arguments are given, the script will show appropriate dialogs)
11 #
12 # Requires:
13 # mencoder
14 # zenity
15 #
16 # Author:
17 # Konrad Siek <konrad.siek@gmail.com>
18 #
19 # License information:
20 #
21 # This program is free software: you can redistribute it and/or modify
22 # it under the terms of the GNU General Public License as published by
23 # the Free Software Foundation, either version 3 of the License, or
24 # (at your option) any later version.
25 #
26 # This program is distributed in the hope that it will be useful,
27 # but WITHOUT ANY WARRANTY; without even the implied warranty of
28 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 # GNU General Public License for more details.
30 #
31 # You should have received a copy of the GNU General Public License
32 # along with this program. If not, see <http://www.gnu.org/licenses/>.
33 #
34 # Copyright 2010 Konrad Siek
35
36 # Auxiliary shorthand for rotating:
37 # rotate INPUT OUTPUT ROTATION
38 function rotate() {
39 mencoder -vf rotate="$3" -o "$2" -oac copy -ovc lavc "$1"
40 }
41
42 CCW_90="90°"
43 CW_90="90°"
44 ROT_180="180°"
45
46 case "$#" in
47 0) # Interactive mode
48 file=$(zenity \
49 --file-selection \
50 --title="Select a video to rotate" \
51 --separator="\n" \
52 )
53 if [ -f "$file" ]
54 then
55 output=$(basename "$file")
56 extension="${output#*.}"
57 output="$(dirname "$file")/${output%%.*}"
58 rotation=$(zenity --list \
59 --title="Specify rotation angle" \
60 --column="Rotation angle" \
61 "$CW_90" "$CCW_90" \
62 )
63 case "$rotation" in
64 "$CW_90")
65 rotate "$file" "$output$CW_90.$extension" 1
66 exit 0
67 ;;
68 "$CCW_90")
69 rotate "$file" "$output$CCW_90.$extension" 2
70 exit 0
71 ;;
72 *)
73 zenity --error --text="No rotation specified."
74 exit 3
75 ;;
76 esac
77 else
78 zenity --error --text "Cannot open file '$file'."
79 exit 2
80 fi
81 ;;
82 1) # Just filename
83 output=$(basename "$1")
84 extension="${output#*.}"
85 output="$(dirname "$1")/${output%%.*}"
86 rotate "$1" "$output$CW_90.$extension" 1
87 ;;
88 2) # Two filenames
89 rotate "$1" "$2" 1
90 ;;
91 3) # Two filenames and rotation spec
92 case "$3" in
93 cw) rotate "$1" "$2" 1;;
94 ccw) rotate "$1" "$2" 2;;
95 *)
96 echo "Unknown option '$3'." >&2
97 echo "Try 'cw', 'ccw' or nothing instead." >&2
98 ;;
99 esac
100 ;;
101 *) # Anything else - show usage
102 echo "Usage:" >&2
103 echo -e "\t$0 [INPUT [OUTPUT [cw|ccw]]]" >&2
104 exit 1
105 ;;
106 esac


The code is also available at GitHub as bash/rotate_video.

Wednesday, February 17, 2010

Shasteriskt

I don't know what to say... I might have inadvertently written a mildly annoying spam bot for Twitter and/or Identica and other stuff of that nature.

Example:
./shasteriskt 'myusername:mysecretpassword' 2 'Bored!' 'Annoyed!'

will post two messages to each of the services (defined in the script, Twitter and Identica by default.

The only use for this I can think of is bumping up your Cursebird stats.

Also, your login and password are not necessarily safe when using this script.

Code:
 
1 #!/bin/bash
2 #
3 # Shasteriskt
4 #
5 # A quick and dirty way to generate a ton of spam to
6 # microblogging serivces. This is a script of low-grade
7 # evil.
8 #
9 # Parameters:
10 # USERNAME:PASSWORD - credentials to services
11 # NUMBER - number of repeats
12 # WORDS - a list of words to post
13
14 # Depends:
15 # curl
16 #
17 # Author:
18 # Konrad Siek <konrad.siek@gmail.com>
19 #
20 # License information:
21 #
22 # This program is free software: you can redistribute it and/or modify
23 # it under the terms of the GNU General Public License as published by
24 # the Free Software Foundation, either version 3 of the License, or
25 # (at your option) any later version.
26 #
27 # This program is distributed in the hope that it will be useful,
28 # but WITHOUT ANY WARRANTY; without even the implied warranty of
29 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 # GNU General Public License for more details.
31 #
32 # You should have received a copy of the GNU General Public License
33 # along with this program. If not, see <http://www.gnu.org/licenses/>.
34 #
35 # Copyright 2010 Konrad Siek
36
37 URLs=( \
38 'http://twitter.com/statuses/update.json' \
39 'http://identi.ca/api/statuses/update.json' \
40 )
41
42 if [ "$#" -lt 4 ]
43 then
44 echo "Usage: $0 USER:PASSWORD NUMBER WORD [ WORD [...] ]"
45 exit 1
46 fi
47
48 credentials=$1; shift
49 total=$1; shift
50
51 words=( )
52 counter=0
53 while [ -n "$1" ]
54 do
55 words[$counter]="$1"
56 counter=$(($counter+1))
57 shifto
58 done
59
60 for i in $(seq 1 $total)
61 do
62 for w in "${words[@]}"
63 do
64 for url in "${URLs[@]}"
65 do
66 curl --basic \
67 --user "$credentials" \
68 --data status="$w" "$url"
69 done
70 done
71 done


The code is also available at GitHub as bash/shasteriskt.

Friday, September 18, 2009

Zentube

Another variation on the theme of zenity. I honestly like the way you can make simple front-ends. In addition, I'm doing something with youtube again, or more precisely, I'm doing stuff with youtube-dl.

So, the problem with youtube is that if you don't have Internet access, you obviously can't really use it, and there are certain instances where it'd come in handy. One such instance is when you're doing language teaching in an Internet-bereft classroom.

So there's youtube-dl to get some videos downloaded, but a person is not always in the mood for fiddling with the shell when preparing their lesson material.

Hence, this script provides the simples of interfaces to download videos via youtube-dl. That's pretty much it. Anyway, I think it's simple and does its job.

Oh, yeah, I played around with the idea of automatically installing a package if it is not available at the time of execution. It's a sort of experiment, to see if it can be done at all. I'm not sure how effective this is though. And it depends on apt and gksudo.

The code:
 
1 #!/bin/bash
2 #
3 # Zentube
4 #
5 # A simple GUI front-end to youtube-dl. All you need to do is run it,
6 # and put in the address of the video, and the back-end tries to
7 # download the video.
8 #
9 # Parameters:
10 # None
11 #
12 # Requires:
13 # youtube-dl
14 # zenity
15 # gksudo & apt (if you want youtube-dl installed automatically)
16 #
17 # Author:
18 # Konrad Siek <konrad.siek@gmail.com>
19 #
20 # License:
21 #
22 # Copyright 2008 Konrad Siek.
23 #
24 # This program is free software: you can redistribute it and/
25 # or modify it under the terms of the GNU General Public
26 # License as published by the Free Software Foundation, either
27 # version 3 of the License, or (at your option) any later
28 # version.
29 #
30 # This program is distributed in the hope that it will be
31 # useful, but WITHOUT ANY WARRANTY; without even the implied
32 # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
33 # PURPOSE. See the GNU General Public License for more
34 # details.
35 #
36 # You should have received a copy of the GNU General Public
37 # License along with this program. If not, see
38 # <http://www.gnu.org/licenses/>.
39
40 # The downloader backend.
41 PACKAGE=youtube-dl
42
43 # Output information.
44 OUTPUT_DIR=~/Videos/
45 EXTENSION=.flv
46 TEMP_FILE=/tmp/$(basename $0).XXXXXXXXXX
47
48 # The quality of the output file can be adjusted here, or you can comment
49 # out this setting altogether, to get the default.
50 QUALITY=--best-quality
51
52 # Exit code constants.
53 SUCCESS=0
54 INSTALLATION_ABORTED=1
55 INSTALLATION_FAILED=2
56 INVALID_VIDEO_ADDRESS=4
57 INVALID_OUTPUT_DIRECTORY=8
58 BACKEND_ERROR=16
59
60 # This is a convenience installer for apt-using distros, e.g. Ubuntu.
61 if [ -z "$(which $PACKAGE)" ]
62 then
63 # Ask whether to attempt automatic install of the missing package.
64 # If the answer is no, then quit with an error.
65 zenity --question \
66 --title="Automatic installation" \
67 --text="Can't find <b>$PACKAGE</b>. Should I try installing it?" \
68 || exit $INSTALLATION_ABORTED
69
70 # Try installing the missing package, or quit with an error if the
71 # attempt is failed.
72 gksudo "apt-get install $PACKAGE" || exit $INSTALLATION_FAILED
73 fi
74
75 # Ask user for the URL of the video.
76 url=$(\
77 zenity --entry \
78 --title="Video address" \
79 --text="What is the address of the video?" \
80 )
81 # If no URL is given, then quit.
82 [ -z "$url" ] && exit $INVALID_VIDEO_ADDRESS
83
84 # Move to the output directory, create it i necessary.
85 mkdir -p "$OUTPUT_DIR" || exit $INVALID_OUTPUT_DIRECTORY
86 cd "$OUTPUT_DIR"
87
88 # Make a temporary file to collect error messages from the downloader.
89 temp_file=$(mktemp $TEMP_FILE)
90
91 # Run the downloader.
92 $PACKAGE $QUALITY --title "$url" 2>"$temp_file" | \
93 zenity --progress --pulsate --auto-kill --auto-close --text="Downloading..."
94
95 # Check for errors, and display a success of error dialog at the end.
96 errors=$(cat $temp_file)
97
98 if [ -z "$errors" ]
99 then
100 # Display successful info.
101 zenity --info --text="Download successful!"
102
103 # Remove temporary file.
104 unlink "$temp_file"
105
106 # Exit successfully.
107 exit $SUCCESS
108 else
109 # Display error dialog.
110 zenity --error --text="$errors"
111
112 # Remove temporary file.
113 unlink "$temp_file"
114
115 # Exit with an error code.
116 exit $BACKEND_ERROR
117 fi


The code is also available at GitHub as bash/zentube.

Wednesday, September 16, 2009

Read selection

And onto further adventures!

After making that zenspeak script I got told that it'd be more useful, if you could enter a whole lot of text into it. So then it dawned on me that maybe having a Gedit plugin like that could be useful.

So, if you got the External Tools plug-in installed in Gedit, you can put this script in there somewhere, tweak it a bit to use your favorite speech generator, voice, etc., and you're all set to never read a single word again.

One drawback: it won't be easy to stop it if you've let it run, so if you make it read a lot of text, it might be troublesome.

I suppose I don't have it in me to really write stuff here today.

The code:
 
1 #!/bin/bash
2 text=`xargs -0 echo`
3
4 SYSTEM=espeak
5
6 if [ -n "$text" ]
7 then
8 echo "Reading \"$text\" with $SYSTEM."
9
10 if [ $SYSTEM == espeak ]
11 then
12 padsp espeak "$text" -v en+f3
13 elif [ $SYSTEM == festival ]
14 then
15 echo "$text" | festival --tts
16 fi
17 fi


The code is also available at GitHub as gedit/gedit_read_selection.

Zenspeak

You can give this one to children. It makes them noisier.

This one's just a simple interface to either espeak or festival: it asks you what to say via zenity and then says it. It doesn't take any arguments, so you start it up with a simple:

./zenspeak

In summary, it's not exactly dragon magic.

The code:
 
1 #!/bin/bash
2 #
3 # Zenspeak
4 #
5 # Provides a simple graphical (Gtk) interface to a speech production system:
6 # either espeak or festival. It's really simple too: you put in some text,
7 # the text is spoken. When you put in zero text, the program ends.
8 #
9 # Parameters:
10 # None
11 #
12 # Depends:
13 # espeak (apt:espeak)
14 # festival (apt:festival)
15 # zenity (apt:zenity)
16 #
17 # Author:
18 # Konrad Siek <konrad.siek@gmail.com>
19 #
20 # License information:
21 #
22 # This program is free software: you can redistribute it and/or modify
23 # it under the terms of the GNU General Public License as published by
24 # the Free Software Foundation, either version 3 of the License, or
25 # (at your option) any later version.
26 #
27 # This program is distributed in the hope that it will be useful,
28 # but WITHOUT ANY WARRANTY; without even the implied warranty of
29 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 # GNU General Public License for more details.
31 #
32 # You should have received a copy of the GNU General Public License
33 # along with this program. If not, see <http://www.gnu.org/licenses/>.
34 #
35 # Copyright 2009 Konrad Siek
36
37 # System for production of sound is selected by the parameter,
38 # or the defaut is used if none were specified.
39 SYSTEM_DEFAULT=espeak
40 SYSTEM=`(( $# == 0 )) && echo "$SYSTEM_DEFAULT" || echo "$1"`
41 echo $SYSTEM
42
43 # System dependent settings for espeak:
44 espeak_speed=120 # default: 160
45 espeak_pitch=60 # 0-99, default: 50
46 espeak_amplitude=20 # 0-20, default: 10
47 espeak_voide=english # list of voices: `espeak --voices`
48 espeak_variant=f2 # m{1,6}, f{1,4}
49
50 # I'm completely pants when it comes to setting up festival, so I won't
51 # even attempt it here.
52
53 while true
54 do
55 # Show dialog and get user input.
56 something=`zenity --entry --title="Say something..." --text="Say:"`
57
58 # If no user input or cancel: bugger off (and indicate correct result).
59 if [ -z "$something" ]
60 then
61 exit 0
62 fi
63
64 # Put the input through either espeak or festival.
65 if [ "$SYSTEM" == "espeak" ]
66 then
67 # Note: the sound is padded within pulse, so that it can be
68 # played simultaneously with other sources.
69 padsp espeak \
70 -a $espeak_amplitude \
71 -p $espeak_pitch \
72 -s $espeak_speed \
73 -v $espeak_voice+$espeak_variant \
74 "$something"
75 elif [ "$SYSTEM" == "festival" ]
76 then
77 # Incidentally, that's all I know about festival.
78 echo "$something" | festival --tts
79 fi
80 done


The code is also available at GitHub as bash/zenspeak.

Monday, July 27, 2009

Uptime and battery state log

Here I go, posting two days in a row.

I got one of those new-fangled Asus Eee PCs recently (with Xandros and not the other thing, obviously) and, being the paranoid freak that I am, I needed to check out how long the battery lasts. And I needed to do that every single time I used it.

So I mashed up a little script for it, and then started adding functionality to it with almost every run, and it sort of grew. So I recently added the traditional getopt stuff, and a license and some basic error checking, and decided to post it.

It needs acpi and uptime to run at all, and if you want to print stuff out to stdout as well, then you need tee.

It should be pretty straightforward to use, but here's an overview anyway.

First, you gotta make sure that the directory for the logs already exists, or that the script will be able to create it on its own. Personally, I do the first one. The default directory is /var/log/uptimed, so you would go:

sudo mkdir -p /var/log/uptimed
sudo chmod a+rw /var/log/uptimed


And basically, you're all set to go. Now you can run it by simply going:

./uptimed &


Or you can use one of the many available options, like adding a prefix, a suffix and printing the output to screen as well as the log file:

./uptimed -s -c "some suffix" -p "some prefix" &


Enough rambling, here's the code.
 
1 #!/bin/bash
2 #
3 # uptimed (uptime daemon)
4 #
5 # Checks uptime and some acpi settings from time to time and logs
6 # that information in a specified file. It's designed to be run often.
7 #
8 # Parameters:
9 # -t | --sleep-time time between checks (default: 6 minutes)
10 # -s | --stdout write info to stdout as well as the file
11 # -f | --file write to a log file with a name like this one
12 # -e | --extension specify an extensionto the log file
13 # -u | --no-uptime DON'T log current uptime
14 # -b | --no-battery DON'T log batery charge
15 # -d | --no-thermal DON'T log current temperature
16 # -a | --all log uptime, battery and thermal (default)
17 # -c | --comment append a comment to each line (default: empty)
18 # -p | --prefix prepend a comment to each line (default: empty)
19 #
20 # Requires:
21 # uptime
22 # acpi
23 # tee
24 #
25 # Author:
26 # Konrad Siek <konrad.siek@gmail.com>
27 #
28 # License information:
29 #
30 # This program is free software: you can redistribute it and/or modify
31 # it under the terms of the GNU General Public License as published by
32 # the Free Software Foundation, either version 3 of the License, or
33 # (at your option) any later version.
34 #
35 # This program is distributed in the hope that it will be useful,
36 # but WITHOUT ANY WARRANTY; without even the implied warranty of
37 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 # GNU General Public License for more details.
39 #
40 # You should have received a copy of the GNU General Public License
41 # along with this program. If not, see <http://www.gnu.org/licenses/>.
42 #
43 # Copyright 2009 Konrad Siek
44
45 # Presets
46 sleep_time=360
47 echo_stdin=false #true
48 filename=/var/log/uptimed/uptime
49 extension=`date +%Y%m%d`
50 uptime_on=true
51 battery_on=true
52 thermal_on=true
53 comment=""
54
55 # Retrieve program parameters
56 options=$( \
57 getopt -o t:s::f:e:ubdac:p: \
58 --long sleep-time:,stdout::,file:,extension:,\
59 no-uptime,no-battery,no-thermal,all,comment:,prefix \
60 -n $0 -- "$@" \
61 )
62
63 # Check if getopts worked as it should
64 [ $? != 0 ] &&
65 exit 1
66
67 # Iterate over parameters and set up the program
68 eval set -- "$options"
69 while true
70 do
71 case "$1" in
72 -t|--sleep-time)
73 sleep_time=$2
74 shift 2
75 ;;
76 -f|--file)
77 filename=$2
78 shift 2
79 ;;
80 -e|--extension)
81 extension=$2
82 shift 2
83 ;;
84 -s|--stdout)
85 if [ "$2" != "" ]
86 then
87 echo_stdin=$2
88 else
89 echo_stdin=true
90 fi
91 shift 2
92 ;;
93 -u|--no-uptime)
94 uptime_on=$false
95 shift 1
96 ;;
97 -b|--no-battery)
98 battery_on=$false
99 shift 1
100 ;;
101 -d|--no-thermal)
102 thermal_on=$false
103 shift 1
104 ;;
105 -c|--comment)
106 comment="$2"
107 shift 2
108 ;;
109 -p|--prefix)
110 prefix="[$2] "
111 shift 2
112 ;;
113 -a|--all)
114 uptime_on=true
115 battery_on=true
116 thermal_on=true
117 shift 1
118 ;;
119 --)
120 shift
121 break
122 ;;
123 *)
124 echo "This is, of course, impossible... Milliways?" >& 2
125 exit -1
126 ;;
127 esac
128 done
129
130 # Create the base directory,
131 dir=`dirname "$filename.$extension"`
132 if [ ! \( -d "$dir" \) ]
133 then
134 mkdir -p "$dir"
135 if [ $? != 0 ]
136 then
137 echo "$0:Directory does not exist and can't be created: $dir" >& 2
138 exit 1
139 fi
140 fi
141
142 # Create the log file.
143 if [ ! \( -e "$filename.$extension" \) ]
144 then
145 touch "$filename.$extension"
146 if [ $? != 0 ]
147 then
148 echo "$0:File does not exist and can't be created: $dir" >& 2
149 exit 1
150 fi
151 fi
152
153 # The main loop thing.
154 while true
155 do
156 # Gather information.
157 [ $uptime_on ] && \
158 uptime=`uptime | tr -s ' ' | cut -f 1 --complement -d ' '`
159 [ $battery_on ] && \
160 battery=`acpi -b | tr -s ' ' | cut -f 2,5,6,7 -d ' '`
161 [ $thermal_on ] && \
162 thermal=`acpi -tB | tr -s ' ' | cut -f 4,5,7 -d ' ' | tr -d ','`
163
164 # Compose the message.
165 message=""
166 [ -n "$uptime" ] && \
167 message="$message$uptime "
168 [ -n "$battery" ] && \
169 message="$message$battery "
170 [ -n "$thermal" ] && \
171 message="$message$thermal "
172 [ -n "$comment" ] && \
173 message="$message#$comment"
174 [ -n "$prefix" ] && \
175 message="$prefix$message"
176
177 # Send message to file, etc.
178 [ $echo_stdin == true ] && \
179 echo -e $message | tee -a "$filename.$extension" || \
180 echo -e $message >> "$filename.$extension"
181
182 # Wait and repeat.
183 sleep $sleep_time
184 done


The code is also available at GitHub as bash/uptimed.