Today i’ve stumbled in this interesting article by Nat Friedman, on his personal Blog, it’s more than 3 years old and still awesome, check these small gems
—
Yesterday morning I proposed a contest to create the best one-line program that would fit inside Twitter’s 140-character buffer. To kick things off, I wrote this 105-character script which displays a small animation:
s="-<";while true;do echo -ne "$s\r";s=`sed 's/->$/-<-/;s/^/;s/-<-/;s/>-/->/;'<<<$s`;sleep 0.1;done
Arturo (or Pupi as his friends call him) wrote a 135-character morse code decoder in shell:
m=etianmsurwdkgohvf?l?pjbxcyzq;p=0;while read -sn1 c;do [ -z "$c" ]&&p=0&&echo&&continue;let p+=c;echo -ne \\b${m:$p:1};let p+=p+2;done
Press ’0′ for dot, ’1′ for dash, and hit space (or enter) as a char separator. Wow!
I learned a few tricks from Arturo’s script. First, he uses the ${} braces operator to take substrings, like so:
${var:offset:length}
This is incredibly useful! You can actually do shell arithmetic in the offset and length parameters, too. So for example,
${var:i+1:a-3}
is valid for shell variables $i and $a. And to find the length of a string, you can use:
${#str}
So str=”foobar”; echo ${#str} will print “6″. You can read more about the braces operator in the bash info page.
Another thing I learned from Arturo’s script is the versatility of the ‘read’ builtin in bash. Pupi uses the -s argument, which causes read not to echo its input (useful for inputting passwords) and -n1 which tells it to only read one character. Also, Arturo uses [ test ] && operation, which is a handy short-hand for an if statement in shell (and other languages).
Pãdraig Brady wrote this excellent screensaver:
tr -c "[:digit:]" " " < /dev/urandom | dd cbs=$COLUMNS conv=lcase,unblock | GREP_COLOR="1;32" grep --color "[^ ]"
Pãdraig makes use of the square-brace character class operator in tr(1) to filter out all the numerals, which bash also supports.
Building on what I learned from Pupi, here is one I wrote that I call paint.sh:
c=12322123;x=20;y=20;while read -sn1 p;do k=${c:(p-1)*2:2};let x+=$((k/10-2));let y+=$((k%10-2));echo -en \\033[$y\;"$x"HX;done
Use the 1 2 3 and 4 keys to move the cursor around the screen. It’s an etch-a-sketch for your terminal!
You can see that I made use of the read -sn1 trick from pupi as well as the braces operator to substring. I also used ANSI escape codes to position the cursor.
And this is one I call rockband.sh:
while read -sn1 p;do s="";for((i=0;i<$p;i++));do s=x$s;done; yes $s > /dev/audio&sleep 0.1;kill %%;done
Use the number keys to play different tones. When you’re done, hit Control-c.
The way it works is that the ASCII value of each character you send to /dev/audio specifies the excursion of the speaker diaphragm (roughly). The ‘yes’ command prints whatever string you give it, followed by a newline character (ASCII 13, pretty low), over and over again. So the longer the string of ‘x’ characters you pass to ‘yes’, and which ‘yes’ prints between newlines, the slower the oscillation of the speaker diaphragm, and the lower the tone. Neat, huh? I learned this trick from my boyhood friend Edward Loper many years ago.
And here’s the last one I wrote:
s=" #55755071317011117011117075557";for i in `seq 2 $((${#s}-1))`; do k=${s:i:1}; for b in 1 2 4; do echo -n "${s:(k&b)/b:1}"; done; echo; done
Miguel submitted this tiny function plotter:
for x in `seq -1 .05 1`; do y=`echo "s($x*8)*10+10" | bc -l`; for p in `seq 0 $y`; do echo -n " "; done; echo "*" ;done
And here’s another plot:
for x in `seq -5 .5 5`; do y=`echo "$x*$x" | bc`; for p in `seq 0 $y`; do echo -n " "; done; echo "*" ;done
Those last three scripts make use of the venerable “seq” command to generate a series of numbers. Miguel uses fractional steps, but if you only need integers you can also use braces in shell, like this:
sum=0;for i in {1..100}; do let sum+=i; done; echo $sum
Ryan Paul of ArsTechnica fame wrote this Ruby script:
proc{|f|f[proc{|x|x+1},0]}[proc{|x,y|proc{|f,z|x[proc{|w|y[f,w]},z]}} [proc{|f,x|f[f[f[f[f[f[f[x]]]]]]]},proc{|f,x|f[f[f[f[f[f[x]]]]]]}]]
Ryan is using the “proc” primitive in Ruby, which allows you to create an anonymous function (like lambda in lisp), and which I didn’t know about even though I’ve been coding Ruby off and on the last few months. He uses Church encoding to encode the numbers 7 and 6, and lambda calculus to multiply them, thus confirming that he is the most awesome IT journalist working today.
Finally, Jay Wren sent in this C program:
main(x,y){for(;x++;) for(y=2;x%y;)printf( ++y/x+"\0%d\n",x);}
of which he is not the original author (and which I suspect was an IOCCC entry), but which is a very compact way of generating all the prime numbers. The author uses the args to main to save space on variable declaration, and the leading null-terminator in the string is a really clever way to select whether or not to print the output without an if statement. Lots of cleverness in there (though the algorithm to find primes is just brute force).
There were too many good entries to declare a winner, and maybe a contest was the wrong idea anyway. But this was a lot of fun. If you want to send me a script on twitter, be sure to send a “@natfriedman” message after, so that I notice you.
Thanks to Fahim Zahid for help creating the mini screencasts.
Update: Be sure to read More Tweetable Scripts for more goodies!
this is indeed awesome,
but why are you copying the whole post without a link to the original, or add anything of your own?
your whole post can be reduced to the first line and a link to http://nat.org/blog/2008/04/ten-tweetable-scripts/
greetings, eMBee.
There is a link to the original post in the first line (the word blog).
Sometime i republish to give more visibility to an article, but you can choose to read it here or there.
Thanks for the feedback.
I think there was a mess up with posting your first example
s="-$/-<-/;s/^/;s/--/->/;'<<<$s`;sleep 0.1;done
As is it gave errors
sed: -e expression #1, char 19: unknown option to `s'
It looks as though there are unterminated s commands given to sed each s command should have three forward slashes.
Modifying it a little I got it sort of working but I had to add my own s commands to sed for the original situation and give the blank line situation something to replace it with.
I modified it like so
s="-$/-<-/;s/^/;s/--/->/;'<<<$s`;sleep 0.1;done
But that doesn’t look right I couldn’t figure out what you where going for.
ouch I see problems with html I need to convert
> to > and < to <
as I was saying I couldn’t get
s="-<";while true;do echo -ne "$s\r";s=`sed 's/->$/-<-/;s/^/;s/-<-/;s/>-/->/;'<<<$s`;sleep 0.1;done
to work I modified it like so
s="->";while true;do echo -ne "$s\r";s=`sed 's/-<$/-<-/;s/^/->/;s/-<-//;s/->/-</;'<<<$s`;sleep 0.1;done
but it doesn’t quite look right