Showing posts with label tcsh. Show all posts
Showing posts with label tcsh. Show all posts

Wednesday, July 13, 2011

tcsh pour les experts...

Bin moi, mon script de prédilection sous Linux, c'est TCSH. C'est ainsi depuis qu'on me l'a "imposé" pour un TP (base de données ou NS2 ... va savoir). Sous SuSE8.2, ça se passait pas trop mal: bonne auto-complétion, coloration, aliases sympa ... Sous ubuntu, en revanche, c'est quasiment le minimex, au point que j'ai longtemps remplacé les fichiers /etc/profile.d/complete.tcsh et autres d'une vieille SuSE sur mes ubuntu fraîchement installé.

Mais ça aussi, j'ai fini par en avoir marre, donc maintenant, j'ai "fait mienne" toute la super-logique en réutilisant le fichier ".csh.expert" prévu pour permettre à un guru du shell (ou à ses sbires, comme moi :-) de contourner les préférences du sysop. Bin pas de bol, même là, les gars d'Ubuntu ont manqué à leurs devoirs. Alors du coup,


diff -burN /etc/csh.cshrc "/MY/etc/csh.cshrc"@@ -1,4 +1,11 @@
 # /etc/csh.cshrc: system-wide .cshrc file for csh(1) and tcsh(1)
+# Expert mode: if we find $HOME/.csh.expert we skip our settings
+# used for interactive sessions and read in the expert file.
+#
+if (-r $HOME/.csh.expert) then
+    source $HOME/.csh.expert
+        goto end
+endif

 if ($?tcsh && $?prompt) then

@@ -14,3 +21,10 @@
        set prompt = "%U%m%u:%B%~%b%# "

 endif
+
+end:
+onintr
+#
+# csh.cshrc end here
+#
+if ( -r $HOME/.tcshrc ) source $HOME/.tcshrc

Me voilà un peu plus chez moi dans cette ré-installation du Lynx sur mon disque de 2To :P

I've never done anything very fancy with MS.bat scripts, nor with Unix scripts while I was a student. I started really understanding what I was doing in scripting with TCSH, in my master years as a student, while running SuSE8.2. It was quite a good system to have TCSH on, with auto-completion, coloring, aliases and all. We don't get half of that on Ubuntu, to the point I usually tweaked /etc/profile.d on any UBuntu I installed.

But at some point, you grow tired of fixing that on every system you clone your home directory. And why would you when it turns out .csh.expert in your home directory allows you to override the sysop's preferences...

Thursday, February 12, 2009

Script powaa!

Bon. Ouvrez un p'tit terminal (tcsh), on va s'amuser ...

display fairy.jpg
setenv FAIRY `eesh -ewait window_list | grep Magick | cut -f 1 -d :`
randomize `find /pingu/photos/ | grep -v thumb` |\
fe - "display -window $FAIRY '%' & sleep 8"
C'est ma manière à moi de me faire un petit diaporama de mes photos sur mon laptop, mode "discret: je travaille mais j'ai besoin de voir un peu mes proches".

J'vous explique ? Bon, tout d'abord, vous devez penser à tous ces programmes comme des "filtres" qui reçoivent des données par un côté (l'entrée standard) et qui en produisent de l'autre côté (la sortie standard). Un élément de base pour interconnecter les programmes est le tube ("unix pipe") représenté par la barre verticale. program1 | program2 attache les deux programmes de sorte que la sortie de program1 est utilisé comme entrée pour program2... Visualisez une usine avec des robots qui bricolent des pièces qui défilent sur un tapis roulant et vous n'êtes pas loin.

Comme certains programmes ne sont pas prévus pour recevoir leurs données sur l'entrée standard mais plutôt comme des arguments sur la ligne de commande, j'utilise aussi les guillemets arrière qui remplace dans une commande une expression par le résultat de son évaluation. Si add et mul étaient des programmes pour additioner et multiplier leurs arguments, on pourrait faire des expressions un peu plus compliquées à coup de add 5 `mul 2 3` qui serait transformé en add 5 6 avant d'appeler le programme add.

I love how scripting expands the possibilities of programming. Maybe I could have experienced something similar with Visual Basic, but that tool has never happened to be available on my Windows systems afaik. The code you see above is a script I use to periodically change one part of my screen's background as if it was a diaporama.

display FILE will just create the window and show one file. then the line with eesh will capture the identifier of that window into some variable and calling display again with -window $FAIRY will make it paint on the existing window instead of creating a new one.

That's already pretty neat, but I can push it further, like scanning through my pictures repository with find, filtering out the thumbnails with grep and randomize the output with a Perl script of mine that isn't even aware it is processing picture file names.

This is possible thanks to the unix pipe | and shell sub-expressions `sub expr` that gets a program called and its output injected as parameter for another program.

Bref, les programmes utilisés ici:
  • display, le programme d'affichage du projet ImageMagick hyper-standard. Par défaut il ouvre une nouvelle fenêtre pour la nouvelle photo, mais avec -window , il modifie l'image de fond d'une fenêtre existante. En l'occurence, cela me changera l'image affichée.
  • eesh, le kit du bricoleur pour enlightenment, utilisé ici pour récupérer la liste des fenêtres. Si vous n'utilisez pas enlightenment, le package wmctrl pourrait faire l'affaire ...
  • grep, le filtre passe partout, en standard dans toutes les distributions Unix, utilisé aussi bien pour retrouver la fenêtre dont le titre contient "Magick" dans la deuxième commande que pour retirer toutes les miniatures dans la deuxième commande
  • find, également un outil standard, liste tous les fichiers à partir d'un répertoire donné
  • cut : pour extraire un champ d'une ligne du type "fichier CSV".
  • setenv <var> <val>: pour donner un nom au résultat d'une exécution (en l'occurence, enregistrer le n° de la fenêtre d'affichage dans la variable $FAIRY)
  • randomize <args> : un p'tit script perl à moi qui renvoie ses arguments mélangés, ligne par ligne.
  • fe - "commande" : un autre petit programme à moi ("foreach") qui applique une commande à une liste d'arguments. Les puristes auraient utilisé xargs ou find -exec.
  • sleep <secondes> : pour marquer une pause entre 2 images, bien-sûr
Chouettos, non ? Allez, les amateurs de VBA. Vous mettez combien de temps pour faire ça ?

Monday, September 15, 2008

Programmatically surrealistic


Earlier in the day, i had an argument with the update-manager of my test machine who was refusing to update my Dapper Drake because of some "hash mismatch" at the mirror. For some reason, i didn't trust the ubunutu forums that state that "this occur when you try to update while mirrors are synchronizing" and finally discovered that the way hashes (that confirm your softwares' authenticity) are managed has changed with Hardy Heron ... Doh. Fortunately enough, someone is still thinking that some user prefer to update from a text console rather than having a "user-friendly" graphical interface but only at the cost of burning a new ISO distribution and moving your feets two level down in the lab.

So my thanks fly to the maintainers of the update-manager-core package and the sudo do-release-upgrade -m desktop trick that did the whole upgrade without pop'ing any window and without silly hashing bugs.

You thought that would have been the weirdest thing around? You were wrong.

With the machine updated, i'm now able to test the new release of that European project i'm working on ... The software has a thing called "the minmex" which spawns thread for various sub-tasks and i thought it would be handy to catch those "logfile " lines it produces on stdout, and process them in a script that would automatically start following each new log. Easy as (s)hell :

# invoke this as:
# sudo bin/minmex | perl myscript.pl
while ($_=) {
print;  # just echo back the filename
chomp;
sleep 1; # just let the minmex actually create the file
system "tail -f $1 &" if (/logfile (.*)/);
print "waiting for more ...\n";
}


Except it didn't worked. Only the "master thread" displayed something. Of course, running a plain "sudo bin/minmex" show you all you wish to know on the console :-/
And of course, as usual with the latest libc6, you don't even see any write(1, ...) in the output of an strace bin/minmex. My colleague Cyril supposed something odd with termcaps, but there was absolutely nothing that sophisticated in the minmex. Just a very plain printf("logfile %s"); ...

Fairly puzzling, don't you think ?

Well, now it started getting funny when i realised that i actually was facing this in the 'master' thread:

mkdir("/tmp/log", 0777) = -1 EEXIST (File exists)
fstat64(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, 0xbf97285c) = -1 ENOTTY (Inappropriate ioctl for device)
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f7f000
write(1, "logfile /tmp/log/26274_"..., 71logfile /tmp/log/26274_anaMinmex
) = 71
brk(0)                                  = 0x806b000
brk(0x808c000)                          = 0x808c000
open("/tmp/log/26274_anaMinmex", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
.

I'm not very comfortable with those termcaps things, but that ENOTTY error clearly suggested that Cyril was right and that the source code was wrong 0_o ... Using plain write(1,...) instead of printf(...) let me see all the stuff i wanted, but that can hardly be called a solution. After a bit crawling in the sourcecode of libc6, i could not find any direct relationship between tcgetattr (the function using that TCGETS argument) and printf, but some reference to glibc-2.6.1/misc/getpass.c did ring a bell in my mind ...
What if the problem was actually coming from the sudo not liking me to redirect the program's output ? what if, for some reason, it *had* to ensure the access to a terminal (e.g. to prompt me for a password) and failed to properly restore the output-to-next process ?

And indeed, running the whole chain in a regular root session has now shown a perfectly regular behaviour, in other terms:
  • either you shouldn't try to redirect stdout when using printf
  • or you shouldn't try to build multitasking programs
  • or you shouldn't try to run those programs as a sudoer
  • and you certainly shouldn't do all these three things "for chaos and maddness awaits thou at thee end" ...
For your mind's sanity, i just hope that you'll never ever find such a post useful. But in case you happen to struggle with such a debugging nightmare, i hope i've got a sufficiently high pagerank to get ahead all these mailing list that discuss about whether a bug is a bug or not and that you'll get a clear understanding of the situation faster than i did...

HAve a nice day,
/Pype, the crazy coder.

edit: the problem seems to be tcsh-specific (e.g. doing the plain sudo bin/minmex | perl myscript.pl in bash will work) and there are two possible (and both equally surrealistic) work-around for those who don't want to switch to bash:
  • sudo -c tcsh "bin/minmex | perl myscript.pl"
  • sudo -c tcsh "bin/minmex" | perl myscript.pl
I'm accepting any explanation for this, and myself strongly suspecting tcsh to do something wrong when building the pipes between minmex and perl...

Sunday, October 14, 2007

/dev/tcp ou netcat ?

En réaction au blog de bodman, qui nous présentait une manière élégante (tirée d'un autre blog: unixjunkie) capable de lancer des requêtes HTTP armé du seul shell "BASH":

exec 3<> /dev/tcp/www.google.com/80
printf "GET / HTTP/1.0\n\n" >&5
cat <&5
exec 5>&-


qui se soldait sur mon ubuntu invariablement par un "bash: /dev/tcp/www.google.com/80: No such file or directory". Intrigué, j'ai un peu cherché sur les forums, puis j'ai téléchargé les sources, et dans le README, je trouve ceci:

9. Why is bash configured with --disable-net-redirections?

It can produce completely unexpected results. This kind of
feature should not be part of a shell but a special. tool. And
that tool has existed for years already, it's called netcat.



aha. man netcat, alors ...


netcat is a simple unix utility which reads and writes data across net-
work connections, using TCP or UDP protocol. It is designed to be a
reliable "back-end" tool that can be used directly or easily driven by
other programs and scripts.
In the simplest usage, "nc host port" creates a TCP connection to the
given port on the given target host. Your standard input is then sent
to the host, and anything that comes back across the connection is sent
to your standard output.


ma réponse de TCSHeur sera donc:
debian> echo "get / http/1.0\n\n" | nc www.google.com 80


Je vous laisse juge ^_^