Wednesday, May 7, 2008

Unix Tricks

1)

From within an executing script, how do I find the directory where the script lives?

A simple pwd doesn't work because it gives the Present Working Directory, and we want to know the directory where the script actually resides on disk. I can't remember the previous solution I came up with, but here's another solution that should work:

#!/bin/bashdir=$(echo $0 | sed -e "s,^\([^/]\),$(pwd)/\1,")echo I live in $dir
Here how it works (hopefully). $0 is the name of the script as it was executed, so this may be foo.sh, ./foo.sh, /tmp/foo.sh, etc.. This gets sent to sed, which then uses a basic regular expression that says "If the first character of $0 was NOT a forward slash, then prepend $0 with my present working directory ($(pwd)) followed by whatever that first character was (\1), then assign this new value to dir". If the first character in $0 is a forward slash, then we were invoked via an absolute path and so we don't want to change anything.


2.



How do I copy a directory structure from one machine to another?


$ tar cf - some_directory | ssh kramer "( cd /path/to/destination; tar xf - )"
tar cf - some_directory creates a tar file of some_directory but the dash (-) tells tar to write to STDOUT instead of writing to an actual file on disk. The STDOUT from the first tar command is piped to STDIN of the next command. The right hand side of the pipe says to log into the host kramer using ssh and run the commands cd and tar xf -. The trick is with the commands "( cd /path/to/destination; tar xf - )". The parens create a subshell, in which the current directory is changed to /path/to/destination, and tar xf - reads from STDIN and extracts the tar file. This STDIN is the same STDIN that was sent to us over the pipe from STDOUT of the first tar command. Thus the directory structure on jerry gets tar'd up, transfered to kramer, then extracted all in one fell swoop.


3)

How do I diff two files on different machines (using Bash)?


$ diff <(ssh -n george cat /etc/passwd) <(ssh -n kramer cat /etc/passwd)
This is just the Bash Process Substitution trick.





How can I run a shell script on a remote host without copying the script out?

One way would be:

jerry:~$ cat myscript.sh | ssh kramer /bin/sh
This one is pretty simple how it works, but it is often overlooked as an option for getting things done. The shell script is written to STDOUT. /bin/sh is executed on the remote server, and it reads myscript.sh on STDIN, thus executing the local copy of the script. This is way convient for some things. The only problem I see with this one is that you can't pass command line arguments to the script.





How can I run long pipe lines of commands on a remote host via SSH without escaping all the meta characters?



jerry:~$ ssh kramer <The only tricks here are the use of a bash here document, and the fact that the command line is typed directly into ssh's STDIN so there's no need to escape things like pipes and semi-colons, etc. However, notice that you do still need to escape dollar signs because they'll still be interpreted as shell variables.





How do I change every occurance of a string in multiple files?

Why, use perl pie!

perl -p -i -e 's/jerry/george/g' *.txt
See perl -h for a description of the flags.

No comments: