Special thanks to Carpet Smoker of Daemon Forums. |
shells
What I hate about programming
Some months ago when it reached Kris Moore’s attention (late as usual) that I had brought up security issues with his Firefox3 PBI, he changed it to something almost as bad. A couple weeks ago, I heard back from Kris that he had [naively] changed the code for making Fx3 the users default browser would no longer run as “root”. After a little more conversation he split it off to something better.
Originally it was a part of the script that runs during PBI installation (and worse then the below script), probably tired of my replies he made an extra wrapper around the Firefox3, that asks the user if they want Firefox3 set default or not, rather then workin’ the user database at install time. (I refuse comment on the following scripts predecessors: if you want to know more, read his SVN). The solution he came up for that wrapper, was to invokes the following code as the user when necessary:
#!/bin/sh
# Helper script to make FF the default browser for a user
##############################################################################
# Get the users homedir
USER="`whoami`"
HOMEDIR="`cat /etc/passwd | grep ^${USER}: | cut -d ":" -f 6`"
if [ -e "${HOMEDIR}/.kde4" ]
then
KDEDIR=".kde4"
else
KDEDIR=".kde"
fi
if [ ! -e "${HOMEDIR}/${KDEDIR}/share/config/kdeglobals" ]
then
echo "ERROR: No kdeglobals file for $USER"
exit 1
fi
TMPKFILE="${HOMEDIR}/.kdeglobals.$$"
TMPKFILE2="${HOMEDIR}/.kdeglobals2.$$"
rm ${TMPKFILE} >/dev/null 2>/dev/null
cat ${HOMEDIR}/${KDEDIR}/share/config/kdeglobals | grep -v '^BrowserApplication' > ${TMPKFILE}
rm ${TMPKFILE2} >/dev/null 2>/dev/null
touch ${TMPKFILE2}
while read line
do
if [ "$line" = "[General]" ]
then
echo "$line" >> ${TMPKFILE2}
if [ "${KDEDIR}" = ".kde4" ]
then
echo "BrowserApplication[$e]=!/Programs/bin/firefox3" >> ${TMPKFILE2}
else
echo "BrowserApplication=!/Programs/bin/firefox3" >> ${TMPKFILE2}
fi
else
echo "$line" >> ${TMPKFILE2}
fi
done < ${TMPKFILE}
# all finished, now move it back over kdeglobals
rm ${TMPKFILE}
mv ${TMPKFILE2} ${HOME}/${KDEDIR}/share/config/kdeglobals
exit 0
which is more secure then the original implementation, and more efficient also. Tonight I sent Kris a casual (read: adapt to need, don’t take as is) suggestion from yours truly:
#!/bin/sh
# Helper script to make FF the default browser for a user
# Should work for KDE3 and KDE4.
##############################################################################
PROG="!/Programs/bin/firefox3"
FILE="./share/config/kdeglobals"
for D in "${HOME}/.kde" "${HOME}/.kde4"
do
cd $D 2>/dev/null || break;
if [ ! -e "$FILE" ]
then
echo "ERROR: No kdeglobals file, unable to set $PROG as default"
exit 1
fi
ed -s "$FILE" <<EOF
/[General]/
/BrowserApplication.*=/
s/=.*/=${PROG}/
wq
EOF
# write your own error handlers
done
exit 0
which should work as far as I can test; since I lack a working KDE install (compiling KDE4.2+ is on my todo list). It’s not perfect, but it sure is nicer then what he had a few months back. I included the a diff of the two scripts in my last message, which may very well go against my decision to “never” send these people patches. But I really don’t care if he accepts it or not, because while I believe in being helpful, I also I do not like doing peoples jobs for them.
I’m a lazy good for nothing creep, but I am lazy of muscle – not lazy of mind. The most productive code I have ever written, is the code I was smart enough /not/ to write in the first place.
Useful way to pass the time
Got bored, have never found something like xkill that I can just say, “xkill somewindowname”. Found xwininfo last week, thought about this hehe:
#!/bin/sh
#
# kill X client by window name
#
if [ -n "$1" ]; then
xwininfo -name "$1" | grep 'Window id:' | awk '{ print $4 }' |
head -n 1 | xargs xkill -id
else
echo "usage: `basename $0` windowname"
fi
xkillname xconsole and poof – the xconsole window is killed, hehe.
Yippie-Kay-Yay Micro$oft SFU !!!
Test one: I wonder if Console is a decent replacement for cmd.exe ‘s terminal emulator — It is
Test two: I wonder if the SFU pdksh can do completion? — It can, just had to find the ‘bind’ commands for it
Test three: I wonder if SFU’s pdksh will work with my %PATH% — it did
Problem one: SFU pdksh seems to require the formal name, e.g. ‘foo.exe’ for programs outside of it’s regular path and runwin32’s search path — That’s ok, I don’t mind much and can alias out stuff like flock.
Problem two: Because SFU follows the unix-style of open it, see if there is a she-bang line (e.g. #!/bin/sh) saying what to run it with, else pass it on to the shell…. It feeds .bat files into it’s pdksh unless they are manually executed, e.g. ‘runwin32 cmd /C foo.bat’ — that is bad, several programs I use wrap themselves in ‘batch’ files on Windows and ‘shell’ scripts on Unix.
Problem three: My universal bourne-based shrc (~/.${USER}_shrc) sets itself to the current Bourne-style shell (e.g. sh, bash, ksh-family, zsh) and Operating System (e.g. BSD, Linux, generic Unix) needs to inspect the $SHELL environment variable to determin what shell to set stuff for. — For some odd reason the SFU pdksh doesn’t seem to set SHELL !!!! To top it off, $USER is not set, but at least the Windows var: %USERNAME% is converted to $USERNAME.
Fix for problem one:
$ mkdir /dev/fs/P/bin # creates P:bin
$ touch binmaker.sh && chmod +x binmaker.sh
$ vi binmaker.sh
#!/bin/sh
BINDIR=/dev/fs/P/bin
for CMD in `echo $PATH | sed 's/:/ /g' | awk '{ print $0 }'`
do
for EXE in `ls $CMD`; do
echo $EXE | grep -E '.*.exe$' > /dev/null &&
ln -s ${CMD}/${EXE} ${BINDIR}/`echo $EXE | sed 's/.exe$//g'` && echo "made link for: ${CMD}/$EXE"
done
done
$ ./binmaker.sh
.... # symlinks all foo.exe in $PATH to /dev/fs/P/bin/foo
Fix for problem two:
Launch a new session of cmd.exe through windows (e.g. not via SFU; use the run dialog, start menu, or desktop /or quicklaunch icon).
U:Terry> echo %PATH% > mypath.win
Return to SFU korn shell (pdksh):
$ touch batmaker.sh && chmod +x batmaker.sh
$ vi batmaker.sh
#!/bin/sh
BINDIR=/dev/fs/P/bin
make_wrapper() {
[ -e $2 ] && return # file exists, no wrapper needed
local MYFILE=`basename $2`
cd $BINDIR && [ ! -e $MYFILE ] && touch $MYFILE
echo '#/bin/sh' >> $MYFILE
echo 'exec cmd /C "set PATH=`cat ~/mypath.win` && `basename $0`"' >> $MYFILE
echo "${BINDIR}/$MYFILE created"
}
for CMD in `echo $PATH | sed 's/:/ /g' | awk '{ print $0 }'`
do
for EXE in `ls $CMD`; do
echo $EXE | grep -E '.*.bat$' > /dev/null &&
make_wrapper ${CMD}/${EXE} "${BINDIR}/`echo $EXE | sed 's/.bat$//g'`"
done
done
$ ./batmaker.sh
... makes wrapper shell scripts in /dev/fs/P/bin/ for all foo.bat in $PATH
The wrapper scripts this creates look like this:
Terry@SAL1600-$ cat bin/irb
#/bin/sh
exec cmd /C "set PATH=`cat ~/mypath.win` && `basename $0`"
Terry@SAL1600-$
it’s neccessary to set the Windows %PATH% before launch, so it can execute the program — using the path from the invocation environment won’t work, e.g. /dev/fs/P/Devel/Langauges/Ruby/bin/irb in SFU Shells but this woudl translate to CurrentDriveLetter:dev/fs/P/Devel/Langauges/Ruby/bin/irb which won’t work. Note, the program must be executed as P:DevelLanguagesRubybinirb.bat in Windows cmd shell, as that is where it is located on my system.
Fix for problem three:
I modified my ~/.profile from OpenBSD to take care of the $USER and $SHELL issues, which is also nice enough to load my custom initialization file.
$ vi .profile
export TERM HOME
USER=$USERNAME; export USER
SHELL="/dev/fs/P/Utilities/Services_For_UNIX/bin/ksh"; export SHELL
echo "Waiting for screen repaint...."
sleep 2
echo 'Korn power !!!'
ENV=${HOME}/.${USER}_shrc
I set the path to the physical rather then the /bin/ksh ‘shorty’ in SFU, so that if I later find any compatibility issues, I can always work around it ‘specifically’ if necessary.
I’m not sure if it is a problem with the Console2-Devel build I’ve installed or with how SFU’s korn shell expects to run. But a few seconds after startup the prompt disappears as if from a ‘clear’, giving any I/O that results in a line being drawn causes a fix. Since I haven’t figured this part out yet, I’ve just ‘side stepped’ the problem. It takes roughly the amount of time to sleep and echo the message before I am returned to my prompt. A quick parse of my $ENV and we’re ready to rock and all the output on the Console tab is from my ${USER}_shrc file.
I copied an old version of initialization file and made a quick edit. In the file I check for the systems unix name and use it to record the operating system type. The Services For UNIX subsystem still identifies itself as ‘Interix’ even though it’s been under Microsoft’s thumb for a bit.
case `uname -s` in
'FreeBSD') isFreeBSD=1
LSCOLORS='CxGxxxxxBxexExcxdx'; export LSCOLORS
;; # FreeBSD
'OpenBSD') isOpenBSD=1;;
'NetBSD') isNetBSD=1;;
'Linux') isLinux=1;;
'Unix') isUnix=1;;
'Interix') isUnix=1;isSFU=1;;
esac
I want to make a few changes to my shrc, but I don’t think they will work *properly* with SFU. My shrc file also pulls in a local ‘extension’ of itself, called ~/.site_shrc that makes things specific to the current system, for example adding the TexLive binaries to my $PATH on FreeBSD and noting the IP address or doing things that won’t work in the shells/v7sh that I use for testing. It looks like I’m going to have to write a site_shrc for Windows hahaha !!!
There’s more then one way to skin a cat, and this bloody hoge-podge of an operating system ain’t gonna best me !!! I will have a decent CLI interface if I’ve got to invoke a hex editor…
Vi, Macs, and Shells
I’ve so got to get or make a Vim plug in or some thing for this.
So far I’ve come to a cross roads, I can keep my editor or I can become more Emacs compatible. On Windows I use PuTTY for a ssh client. I don’t know what the terminal emulator is but it sucks. When working on Vectra I effectively have no insert/home keys e.t.c. or Numpad which is bad because I’m accustomed to using the home and end keys in my line editing. This means ether live with only cursor keys and backspace for line editing or relearn the Emacs navigation commands. Control+key is used, b for back one char, f for forward one char. p for previous command (up) and N for Next command (down). e for end of line while a is used for end and home key replacements. Using the meta key (generally alt) turns this up a notch and uses larger units such as forward a word instead of a char. I’m used to using control+u and control+w in line editing – I don’t know if control+w has effect in Emacs but control+u doesn’t.
Needless to say I don’t like Emacs ! I used XEmacs as my editor at first but I fell in love with Vim after I started getting into shell use. You could say learning the shell helped me learn Vim and vice versa. I didn’t like vim at first and I’m only now starting to use gvim off windows (konsole is better then cmd.exe). I’m very used to Vim so I am also used to Vi. My vimrc file makes it easier to use but since Vectra is very light on the software I didn’t install vim. Vi is good enough and ee for when I’m just pissed.
Vim/Vi is very simple to use once you get the hang of it, Emacs is just wrist strain. So now I ask my self the question: What about Vi editing mode? The Bourne and Korn shells support it as does the Z shell AFAIK. However I use tcsh which does not. So if I want to use this editing mode that means use another shell. Vectra only has sh and tcsh. Being FreeBSD the csh is actually tcsh but not like how bash is commonly GNU/Linuxes sh. FreeBSD uses ash as s, a very light Bourne shell clone. I could install any other shell I want really and a ruby shell would be kind of cool if it could fuse an interactive shell, scripting and ruby into one package. The problem is if I get used to vi line editing in a shell I’ll be ruined for any other shell !. I’ve yet to decide but to be honest with the Vi editing mode I think sh is livable. It nets the use of cursor keys and command history.
nvi/Vim is very simple. Vi is a modal editor, if you press escape you are in a command mode, if you press “i” or insert you are in insert mode and it’s like most text editors. You litterly change the entire keyboard into/out of modes. In insert mode your keys always insert chars, most consoles let you use the arrow keys, home/end/delete/backspace like normal. In normal mode which can be reached by pressing escape. Every key stroke is a command or switches to other modes. You can move the cursor with the h,j,k,and l keys. The h and l keys move left and right while the j and k keys move down and up. I’ve heard that Bill Joys console had arrow keys on these so that’s probably why they are used this way. It was a little weird at first but now I’m getting used to it. I’ve generally used the cursors.You can delete a char using the “x” key.
You can delete directionally by prefixing a movement key with d. So dh and dl deletes one char to the left or right. Pressing dj or dk will delete the current line and the line below or above. To kill the whole line use dd. You can repeat commands by appending a number, example: dd3 will delete 3 lines. You can move to the start or end of line by pressing ^ and $ this also works with d. You might notice ^ and $ from some studies in regular expressions – I do from a bit of sed/grep/awk learning. You can move forward and back a word at a time with the w and b keys. Much faster then control+key combo and easier on the wrists IMHO! Pressing i puts you into insert mode to enter text, pressing v puts you in visual mode. Escape will bring you back to normal mode. I never used visual mode very much at first but now I find it useful. In visual mode most normal mode commands for movement work the same. Yet when you move the cursor you always highlight or “select” text. You can copy it or “yank” it with the y command and put or “paste” it with the p command. If you want to cut it use the c command. Usually after a cut I think Vim puts you in insert. Pressing : gives you a little command line.
Here you can enter commands but internal and external, set options and more. To edit a file type e /file/name after pressing : for speed I bound ; to do the same as : in my vimrc. To save it’s :w also know as write ! To quit it’s :q note that you press the ” : ” you don’t type it as part of the command. You can override it by suffixing it with a !. Example: force a quit by doing a :q!
We can run shell commands by prefixing them with a “!” like this :!ls ~/Documents. File name completion works and a UNIX shell is better at it then cmd.exe (vim is very portable). Vim might seem a bit awkward at first but once your used to it it’s very fast and effeienct. TO get help type :help to get context sensitive help try :help topic_or_cmd
Using vi line editing in a shell works the same was using Vi only you start off in insert mode instead of normal mode. I haven’t decided what to do yet.
Ya know whats funny…. I started out to write a short post about my feelings but I end up trying to knock out a Vi/Vim intro before my batteries run out.
All roads lead to Vi !!!