aru Posted January 15, 2003 Report Share Posted January 15, 2003 arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Fri May 10, 2002 2:59 pm Post subject: Bash tips and tricks _________________________________________________________________ This is going to be my tips and tricks tribute to the bash shell, which I believe is the soul of the GNU/Linux OS. I'll post here any useful tips and tricks I'll find focusing to the bash shell. Please feel free to contribute to this section with your own set of tips and tricks. At this time: 1. Bash history tips 2. The unknown $CDPATH variable 3. More on cd (typing errors) 4. Key bindings in bash shell 5. Bash? Please, help me! 6. The revenge of cd Twisted Evil (pushd/popd) 7. A couple of articles on tab completion including the very last features (thanks to frew and tom) 8. Here-Documents 9. First post of "SHELL PARAMETER EXPANSION" series 10. Trick: A fast way to comment-out blocks of script code 11. Using functions instead of aliases at .bashrc 12. A bizarre single-line-command to empty system logs Last edited by arusabal on Sat Oct 12, 2002 4:31 pm, edited 20 times in total arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Wed May 15, 2002 10:04 pm Post subject: _________________________________________________________________ Some bash-history tips The usage of the bash-history feature could be as fun as helpful, also it can save a lot of time if you are one of those who use bash-terminals for everything (if you are not, what the hell are you doing here with Linux Mr. Green ...just kidding Wink ) I'm not going to talk in extent about the usage of bash-history, I only want to show you a couple of tips. If you want to learn more about it you can take a look to the chapter 7 of the Bash Reference Manual (such as ramfree "pointed" long time ago, should be under every linux user's pillow Wink ) Here are the tips: ~]$ !n --Will execute the line n of the history record. ~]$ !-n --Will execute the command n lines back. ~]$ !! --Will execute the last command. As !-1 or "up-arrow + return" ~]$ !string --Will execute the most recent command starting with the given string. In my experience string is just the first characters of the first word of the command, so don't use space characters. ~]$ !?string[?] --Will execute the most recent command containing the given string. The last "?" may be omitted if the string is followed by a new line. So if the string includes space characters or similar close it with "?". This can be used to avoid the error that appears with !string when used with long strings. ~]$ ^string1^string2 --String2 will substitute string1 on the last command. Cool, isn't it? This is equivalent to !!:s/string1/string2/ which is cooler Wink Any one feels a bit like in vi? $HISTIGNORE or How-To improve the history usage: You might want to set up the shell variable $HISTIGNORE to avoid having consecutive duplicate commands or unuseful commands appended to the history list. So you'll get rid of the never ending story of hitting the up arrow trough simple and repetitive commands. Here is an example of usage: export HISTIGNORE="&:l[sl]:[fb]g:exit" Setting this way the $HISTIGNORE, the consecutive duplicated commands, the simple calls to ls, ll, fg and bg commands without arguments, and calls to the exit command will not be appended to the history list, so navigate though it will be much easier. Bash-history has many other interesting things, take a look to the manual! ...and forgive me for the emoticons abuse Rolling Eyes Last edited by arusabal on Thu May 16, 2002 5:38 pm, edited 1 time in total arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Wed May 15, 2002 10:17 pm Post subject: _________________________________________________________________ The un-known $CDPATH shell variable This is a little known, *even to me* (as I discovered it tonight Wink ), shell variable. CDPATH does for the cd built-in command what PATH does for executables. Please try it, you'll get surprised. For example: Code: ~$ export CDPATH=~:/mnt:/usr/share/docs:/usr/src/RPMS:/usr/local/ So once you set it, cd win_c would take you to /mnt/win_c/, or just typing cd HTML would take you to /usr/share/doc/HTML/.... Interesting, isn't it? arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Wed May 15, 2002 10:48 pm Post subject: _________________________________________________________________ More on cd stuff cdspell Have you ever got upset because you need to retype a cd to some directory command just for a little spelling error? Well that can be avoid if you set on the cdspell option. Just open a bash terminal and type: shopt -s cdspell Now if you type: cd /isr/src #<--- notice the 'i' Shocked you'll get [arusabal@paleo /usr/src]$ Linux is so cool! Ofcourse you can set it to your bash_profile file, so every time you open a bash terminal you'll be helped in minor spelling errors Wink arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Sat May 18, 2002 11:21 pm Post subject: _________________________________________________________________ Key Bindings Every one knows how to use the arrow keys to navigate trough history records, how to move forward and backwards along the command line, how to use command completion hitting the tab key, how to use the init and end keys, or other common combinations of keys, but during a bash terminal session you can use many other useful key bindings. Here I show you a list of the, to me, more useful ones: Some common command line editing key-bindings: Ctrl-l (as Ctrl-"L" not 1 or I) Clear the screen (terminal) Same as `clear`, but can be used while writing a command without loosing the typing. Ctrl-k Kill the text from cursor position to the end of the line. Ctrl-x backspace Kill the text form cursor position to the beginning of the line. Ctrl-a Move to the start of the current line. Ctrl-e Move to the end of the current line. Alt-b Move backwards to the start of the current word or the previous. (text mode only, doesn't work in X) Alt-f Move to the end of the current word. (text mode only) Ctrl-r Reverse search history: search backwards starting at current line and moving up incrementally (see some posts above for more info). Some other curious keybindings: Alt-u Uppercase the current word. (text mode only) Alt-l ("L") Down case the current word. (text mode only) Alt-l ("L") Capitalize the current word. (text mode only) There are dozens of keybindings!! The default line editing interface is emacs-like, if you are a vi fanatic you might want to use a vi-style line editing interface, so to switch betwen modes use this options: set -o vi #vi-style set -o emacs #emacs-style Resources: Here are some files you might check: /etc/inputrc #System wide key bindings; you can re-read them any time by clicking ctrl-x Ctrl-r. .inputrc #User's own settings man 3 readline #Full information on Key Bindings and a list of them (many doesn't work on X) arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Mon May 20, 2002 5:33 pm Post subject: Getting help _________________________________________________________________ Bash? Please, help me! You don't have any idea of what shopt does? Are you writing an script and it is reporting a syntax error? Did you ever forget how to use the if command? Use the help sytem!!! There are two ways of getting instant help in bash, the first one is the ultra-known trick of looking into the man bash page Shocked , there you'll find all the info about bash shell/scripting you may need; But although using the man page is a great resource of help and info, this can be some times a bit nasty because that page is one of the looooooong ones Wink . The second way of getting instant help is the help built-in command, this one is a real fast way of getting instant help on all the bash built-in commands and its syntax. Here is an example of its usage: help syntax: help [-s] COMMAND Code: [user@host user]$ help if if: if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi The if COMMANDS are executed. If the exit status is zero, then the then COMMANDS are executed. Otherwise, each of the elif COMMANDS are executed in turn, and if the exit status is zero, the corresponding then COMMANDS are executed and the if command completes. Otherwise, the else COMMANDS are executed, if present. The exit status is the exit status of the last command executed, or zero if no condition tested true. [user@host user]$ Also, if you want a shorter output, maybe you only need to refresh your memory with the right syntax of a command, just use the option -s as follows: Code: [user@host user]$ help -s unset unset: unset [-f] [-v] [name ...] [user@host user]$ And finally, if you want a quick reference or a list of all the built-in commands, you'll just need to call help without arguments Wink arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Mon May 20, 2002 6:50 pm Post subject: _________________________________________________________________ The revenge of cd (the directory stack) Lets suppose that you are working in the directory /usr/local/src/some_cool_program_but_with_a_long_name-0.0.123-beta/sou rce/ , you read the README file and then you notice that you have to edit some files in /etc , others in your /home directory, install some dependences form /mnt/cdrom/Mandrake/RPM/ and then go back to the program's source directory to compile it... Arrghh!!!! do I need to type again that long path???? No! you are lucky, there is something cool in the bash shell called the directory stack Cool Lets rewind a bit. We were in /usr/local/src/some_cool_program_but_with_a_long_name-0.0.123-beta/source/ , remember? Then to change to /etc instead of using cd /etc we'll do pushd /etc. Doing such thing the directory where we were is saved on the top of the directory stack. Once we finish all the work, installing, editing..., to go back to the original original directory, we'll only need to execute the command popd, and we'll be back again in /usr/local/src/some_cool_program_but_with_a_long_name-0.0.123-beta/source/ (Cool, isn't it?) Epilogue: The Directory Stack is a list of recently visited directories. There are 4 bash built-in commands dedicated to it: * dirs: Display the list of the currently remembered directories. That is also available from the $DIRSTACK shell variable. * pushd: Adds directories to the stack as it changes the current directory. * popd: Removes specified directories from the stack and changes the current directory to the directory removed. * dir: (not used in mandrake because of the default alias!!). Makes the current directory be the top of the stack, and then executes the equivalent of 'cd dir'. Check the man page (or the help built-in) to navigate through the stack and to check which are the options that those commands accept. frew Senior user Joined: 01 Jun 2002 Posts: 214 Location: Mississippi Post Posted: Sat Jun 01, 2002 10:24 am Post subject: don't forget the tab button _________________________________________________________________ I know you didn't ask for this one, but its a lifesaver once you get used to it. Ever have to type in a program name thats obscure or a filename too? well this should help. say you want to open a file called some_cool_program_but_with_a_long_name-0.0.123-beta.txt and you want to edit it with your favorite editlor. well instead of copy/pasting or typing that whole thing you type vi some<tab> and it will complete it unless there is another file that begins with some. arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Sun Jun 09, 2002 2:32 am Post subject: Re: don't forget the tab button _________________________________________________________________ Thanks frew for your tip! You might want to check the following post with the newer and cooler bash tab completion feature Wink arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Sun Jun 09, 2002 2:36 am Post subject: _________________________________________________________________ bash Autocompletion on Steroids... Really cool!!! Stolen from tom's mandrakeforum article Wink Posted by tom on Saturday, June 08 @ 05:00:00 PDT bash is the standard shell on Linux. If you've ever used it (*grin*), you will know about the auto-completion feature which expands file and directory names in path names upon hitting the TAB key. How about auto-completion for 'rpm', 'tar', 'zip', 'chown', 'mount', 'man', 'cvs', 'ssh', image, document and sound files? No problem ... Get the 2.05a bash RPM from Cooker. Notice that this is a package in development and its use is not supported by Mandrakesoft. Works fine here, though. Get the 'bash-completion-[date]-[rev].noarch.rpm' from Ian Mcdonald's website and install it. OK, let the fun begin ... 1. Getting the right file at once: Code: $ ls d* dictionary.lst dwun-0.96e-1.i386.rpm dwun- 0.96e.tar.gz $ tar tzf d[TAB] auto-completes to the only file of those three which can be listed by 'tar', dwun-0.96e.tar.gz. The same for rpm: Code: rpm -qpl d[TAB] auto-completes to the only RPM archive starting with 'd', dwun-0.96e-1.i386.rpm. This behaviour is preconfigured for a load of file types, including PDF, image and sound files. 2. List options: Code: cvs [TAB] lists all available options to the 'cvs' command. Also works for tar and rpm. 3. Complete arguments: Code: man 5 re[TAB] regexp_table relocated resolv.conf resolver Especially useful with RPM: Code: rpm -e ope[TAB] openssh openssh-server opera openssh-clients openssl 4. List available arguments: Code: ssh [TAB] lists all servers in your .known_hosts file as argument. Also works with scp. Code: mount [TAB] lists all configured mount points. This is but a very short list of the possibilities now open to you. Have a glance at '/etc/bash_completion' to see what commands are covered and try them out, or configure the file to match your personal preferences (it's weekend anyway Wink ). As of version 20020601, some things do not work (yet). The 'service' and 'chkconfig' autocompletion requires an extra patch to bash-2.05a. 'urpmi' and friends are listed in '/etc/bash_completion', but don't work for me. Nevertheless, it's quite an amazing feature, and if you spend any considerable lenght of time on the shell, you really, really *want* this. Smile <end of quote> Nothing to add, seems really, really cool Cool The only thing is that I hope that this feature won't eat my P200MMX resources Confused ... I'm going to try it! arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Sat Jul 06, 2002 9:47 am Post subject: _________________________________________________________________ Here Documents Back with this anarchic tribute, today I'm going to introduce the redirections from "here documents"... (maybe some day I'll make a deeper post talking about redirections, but not today). But, what are the "here documents"? It's just a type of redirection that instructs the shell to read the input from the current source until a line that contains only a previously defined word (whatever word). Every line read up to that point is used as input. This kind of redirection is very useful in bash scripts, but also very helpful in shell mode. The format of the "here documents" is something like this: Code: << word document line 1 document line 2 ... document line n word or: Code: <<- word document line 1 document line 2 ... document line n word When used with '<<-' the "here document" is allowed to be indented; which will be much more pretty inside your scripts Wink Now here comes the fun (a couple of usage examples): *) As a replace of long "echo" strings inside a script . Some times I feel that is somewhat esthetically ugly to use many instances of "echo" or to use "echo -e" filling the text string with dozens of echo tags (n t ...). This is much more pretty: Code: ...your code... function helper() { cat <<- _END Usage: command -[uvhctdsat] file where: -u is required when... -v bla, bla, bla ... more blas ... if you need more help please contact to l_torvalds@linux.org GNU license... bla bla... _END #here ends the here document } ...your code... Doing the same thing with "echo" would have been terribly ugly. With the "here document" your script will be much more elegant. *)Just another example, this time focused to command line: Usage of the here documents as a fast resource of creating multiple input lines when you are working in command line mode. The example shows how to quickly instruct wget to download multiple files from different places: Code: [arusabal@mycomp ~]$ xargs wget -c << _Packages http://www.kernel.org/pub/linux/kernel/people/rml/preempt-kernel/v2.4/ preempt-kernel-rml-2.4.18-5.patch http://www.zipworld.com.au/~akpm/linux/2.4.18-rc1-low-latency.patch.gz http://www.kernel.org/pub/linux/kernel/v2.4/linux-2.4.18.tar.gz _Packages I'm leaving to your imagination other useful implementations of the "here document" concept Note: there is no need at all to use "_" at the beginning of the delimiter word, but I love to do it Cool arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Sat Aug 10, 2002 10:08 pm Post subject: _________________________________________________________________ here is something very interesting for the dyslexics --like me-- that I've just discovered while surfing at http://bulmalug.net (spanish). It's just another key binding to add to the list: Ctrl-t will transpose the two characters close to the cursor For example, if you type a lot, it is quite common to change the order of the characters: Code: $ sl [ctrl-t] will be 'magically' converted to: Code: $ ls arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Mon Sep 09, 2002 1:30 pm Post subject: SHELL PARAMETER EXPANSION (1) _________________________________________________________________ SHELL PARAMETER EXPANSION (1) Squeezing bash variables at maximum! This will be the first post of a series where I'll write about the awesome world of SHELL PARAMETER EXPANSION. If you are usually using expressions such as: [user@host ~]$ find . -regex ".* .*" -exec sh -c 'mv "$0" "${0/ /_}"' '{}' ; Then you probably will find this series of postings unuseful or very basic leveled... I'm not a guru, you know that Rolling Eyes But anyhow, if that's your case, you are very welcome to participate by PM me any suggestions or examples you'll want me to include here Wink If you are staring at the above expression and you have any/many difficulty to understand what the hell is that stuff, but you feel that behind it there is something plenty of fun, then this series of posts is written for you!!! Smile I'll try my best to introduce you the 'Shell Parameter Expansion' bash features in an useful way: with plain explanations and, more important, with as many examples as I'm able to write/find!!! I'll try to post each time a case of shell parameter expansion with useful examples. But as I'm a *lazy guy* I can't say which will be the rate of postings that I'll follow. Notice that this will be a series of posts! so if you feel there is something missed, don't be impatient! everything will be covered at its time! Again feel free to contribute to this series by PM-ing me any useful examples you want to share with all of us Smile ...and sorry for my english arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Sun Sep 29, 2002 12:32 pm Post subject: Trick: A fast way to comment-out blocks of script code _________________________________________________________________ Trick: A fast way to comment-out blocks of script code Very useful for debugging purposes ("Anonymous Here Documents") (I know, it is supposed that I'm writing a "Bash Parameter Expansion Series of Posts" for this thread... but I don't have enough time this days for anything Crying or Very sad ) Very often is useful to comment out blocks of code while you are writing a new script and you want to debug it. There are many ways to do this, the easiest way is to add a '#' character at the very beginning of each single line of the code block. That way means to spend many time editing line by line the code adding that '#' character, and after the test is finished, you'll need to remove, again, line by line the '#'. Certainly there are several ways to improve the commenting with '#'. For example, if you write code with vim, the commands: :<fist line number>,<last line number>s/^/# (To comment a range of lines) :<fist line number>,<last line number>s/^#// (To uncomment them) should do the job in a very fast and efficient manner. But THAT's NOT Bash! So as this is BASH tips&tricks, I propose you a cooler way to comment out blocks of code using just a couple of BASH features combined. Those features we'll need are: the 'Here Documents' and the bash-built-in ':'. The Bash built-in command ':' does nothing apart of expanding arguments and performing redirections. Really, it does nothing, but is very useful in many situations, for example to protect some cases of Parameter Expansion (we will see some examples in future posts), or at loops (it is an equivalent of the command 'true', see it's man page), or here, to use combined with the "Here Documents" to comment-out blocks of code creating an "Anonymous Here Doc". Its return status is always zero (=true). The Here Documents were explained in detail some posts above. Back to the trick, let's suppose we have a script like this: Code: #!/bin/bash var1=something var2=otherthing bla,bla,bla ... more code if [something]; then more things else some more fi other code here while condition; do code done and the end code exit 0 #end of script Now, imagine that something goes wrong with the script, and we think that is due to the "end code", so we want to test just the end code, but not the if block and the while loop, so we can comment those two blocks of code by an "anonymous here document": : << _COMMENTED_BLOCK code line1 code line2 ... _COMMENTED_BLOCK so the at the above script this will be: Code: #!/bin/bash var1=something var2=otherthing bla,bla,bla ... more code : << _COMMENT if [something]; then more things else some more fi _COMMENT other code here : << _COMMENT while condition; do code done _COMMENT and the end code exit 0 #end of script And when we execute the script the code inside the "anonymous here documents" wont be seen by the interpreter (that's not completely true, but explaining it will be beyond this post Wink ). This is a superb way of debugging comfortably and fast long bash scripts. You can also use the "anonymous here documents" to create self-documenting scripts, ie: Code: : << _DOCUMENTATION The utility of this script is to be used as... ... then the parameters used should be... ... TODO: * Add code to do... * Check that thing... ... _DOCUMENTATION so you'll see the documentation only when you open the script in an editor. And that's it. I really hope that this could be of some utility for you! arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Thu Oct 03, 2002 11:53 pm Post subject: Using functions instead of aliases at .bashrc _________________________________________________________________ Using functions instead of aliases at .bashrc This post has been written after a hard complaint by ramfree ( Crying or Very sad ) at help with a bash alias, and thanks to 87GTR who started that thread and joehil for providing a couple of great examples. Very Happy In .bashrc, among other thinks you can place aliases and functions. When you open a new bash session (independently(*) if it is a login session or not) the file .bashrc gets sourced(**). That means that all what you put in there is available for you during the session. Bash aliases are a great way to write simple shortcuts for long commands: alias whops="ps aux | grep -v USER | cut -d' ' -f1 | sort -u" alias lp='lp -d $PRINTER' # Use an environment variable to define the default printer alias netscape='/opt/netscape/netscape' But despite of their inherent advantages, aliases lack of many features that one would desire in some cases, ie: they can't take arguments (I don't mean arguments for the program called by the alias, but arguments to the alias itself): for example: $ alias cd2iso='dd if=/dev/scd0 of=/tmp/$1' will never work because $1 will be expanded to an environmental variable named 1, if any. So: $ cd2iso image.iso will result in "dd if=/dev/scd0 of=/tmp/ image.iso" So in these cases, the concept of function in bash becomes very useful. Shell functions are just a way to group commands using a single name for the group, here you can see that are somewhat related to aliases, but in a deeper sense functions are more related to scripts. Functions can accept arguments, and like in scripts, those arguments became the positional parameters during its execution. Also notice that variables defined inside a function are local variables, so they won't be seen by the parent shell after the function ends its job. Functions are declared using this syntax: Code: [ function ] name() { command-list; } or [ function ] name() { commands ... more commands } So in the above example, if instead of using an alias you use a function, you'll achieve your goal: function cd2iso() { dd if=/dev/scd0 of=/tmp/$1; } # (see the original thread for a slightly different implementation of this function.) and thus: $ cd2iso image.iso will result in: "dd if=/dev/scd0 of=/tmp/image.iso" You can create your functions as complex as you wish (they can be used, in our context -sourced by .bashrc-, as highly available scripts). joehill posted these excellent and useful examples of functions that can be declared within .bashrc: Code: function mp3ren() { for i in *.mp3; do mv "$i" `echo $i | tr ' ' '_'`;done; } function mp3dec() { for i in *.mp3; do lame --decode $i `basename $i.mp3`.wav; done; } And I propose, using "parameter expansion" (***), this correction to avoid the usage of external commands for a "higher" performance: Code: function mp3ren() { for i in *.mp3; do mv "$i" "${i// /_}";done; } function mp3dec() { for i in *.mp3; do lame --decode $i ${i%".mp3"}.wav; done; } To end, just this quote from the Bash Reference Manual: "For almost every purpose, aliases are superseded by shell functions". I really hope that this post had been somehow useful for you! Very Happy (*) To achieve this you'll need to be sure that .bash_profile/.profile sources .bashrc (but that's another history). (**) Bash reads and executes commands from .bashrc but in the current shell not in a subshell. That fact means that its variables, its aliases and its functions are available during the session. (***) I'll post the dedicated series soon (when I'll have more free time) Smile guest72485 Frequent user Joined: 05 Jun 2002 Posts: 56 Post Posted: Fri Oct 04, 2002 10:47 am Post subject: _________________________________________________________________ hey thanks buddy, that was helpful DOlson Moderator Joined: 16 Apr 2002 Posts: 2393 Location: Canada Post Posted: Sat Oct 05, 2002 6:04 am Post subject: _________________________________________________________________ WOOHOO!!!!!!!!!!!!! function mkcd() { mkdir $1; cd $1; } I've always wanted to do that!!!!!!!!! Alias sucks! joehill Senior user Joined: 09 May 2002 Posts: 217 Location: Toronto, Canada Post Posted: Sat Oct 05, 2002 6:44 am Post subject: _________________________________________________________________ sweeeeeeeeeeeet good thinkin monsieur! (i know how much you love that) DOlson Moderator Joined: 16 Apr 2002 Posts: 2393 Location: Canada Post Posted: Sat Oct 05, 2002 7:16 am Post subject: _________________________________________________________________ Haha. I wanted to do that forever. I tried a bash script and everything. Nothing worked properly. arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Sat Oct 05, 2002 8:56 am Post subject: _________________________________________________________________ DOlson wrote: WOOHOO!!!!!!!!!!!!! function mkcd() { mkdir $1; cd $1; } Cool! But this version will be better, since you'll prevent errors caused by the missing of an argument (destination dir): function mkcd() { mkdir ${1?"error; usage: mkdir <new directory>"} && cd $1; } Thanks guys for your posts, but damn! I'm very frustated right now! what about the other 12 articles!!!!!!! you are only interested in the last one. That gives the reason to ramfree Crying or Very sad Laughing ramfree17 Moderator Joined: 18 Apr 2002 Posts: 1262 Location: Philippines Post Posted: Sat Oct 05, 2002 4:21 pm Post subject: _________________________________________________________________ because thats the only one we could use on a day to day basis. Very Happy but dont stop aru, who knows, i might have to use the others someday. but first i have to remember them and that means reading them once again.... hehehehehe.. ciao! cannonfodder Moderator Joined: 16 Apr 2002 Posts: 1056 Location: Rochester, NY, USA Post Posted: Sat Oct 05, 2002 4:54 pm Post subject: _________________________________________________________________ I like this set of alias, its real fun! alias bendover='clear' alias aim='ll' alias kickme='bendover;aim;kickme' Rolling Eyes DOlson Moderator Joined: 16 Apr 2002 Posts: 2393 Location: Canada Post Posted: Sat Oct 05, 2002 8:59 pm Post subject: _________________________________________________________________ arusabal wrote: DOlson wrote: WOOHOO!!!!!!!!!!!!! function mkcd() { mkdir $1; cd $1; } Cool! But this version will be better, since you'll prevent errors caused by the missing of an argument (destination dir): function mkcd() { mkdir ${1?"error; usage: mkdir <new directory>"} && cd $1; } Thanks guys for your posts, but damn! I'm very frustated right now! what about the other 12 articles!!!!!!! you are only interested in the last one. That gives the reason to ramfree Crying or Very sad Laughing I don't make misteaks. arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Sat Oct 12, 2002 4:17 pm Post subject: _________________________________________________________________ A bizarre single-line-command to empty system logs Another day to day "usable" trick Rolling Eyes Today I'm very bored, so after a PM from "ian malcom" about logrotate, my ill mind decided to write a single line command to do the following: 1. Empty all the log files from /var/log, saving just the last 50 lines of each one. 2. Delete the useless (at least for me) *.gz log files. 3. Do it recursively in all the /var/log tree. 4. Must be a single line command. 5. It has to be fun, because I'm bored. Previous status: Code: root@host]# du -sh /var/log 193M /var/log There were 21 directories and 145 files (where 50 were .gz files) The single-line command: Code: root@host]# find /var/log -type f -exec sh -c '[[ "${1##*.}" == "gz"]] && rm $1 || (tail -50 $1 > ${1}.tmp && cat ${1}.tmp > $1 && rm ${1}.tmp)' '{}' '{}'; The result: Code: root@host]# du -sh /var/log 665k /var/log and the tree command shows: 21 directories and 95 files. Despite the command syntax is quite bizarre, you'll must admit that it is coooool!!!! Cool The explanation: First the most difficult here, the trick with find: Instead of executing the commands directly to the "-exec" find flag, which is almost impossible, I open a sh session with a -c flag (just reads and executes commands (and finally exits) from the string '<insert here the code>' , and any remaining argument is seen as positional arguments, that's why there are those '{}' '{}' <-- really only one is needed, but then the argument will be $0 which might confuse with normal positional arguments in scripts). For those who don't know it, '{}' is the way find shows its search results to the -exec part. To end with find, "/var/log" is the searching path and "-type f " means only files. Now the "sh" part (remember that the searching results generated by find are passed one by one as $1 to sh -c): Code: [[ "${1##*.}" == "gz" ]] && rm $1 || (tail -50 $1 > ${1}.tmp && cat ${1}.tmp > $1 && rm ${1}.tmp) The first part, is just a conditional construct: Code: [[ "${1##*.}" == "gz" ]] That code will return true if the string that results in the "parameter expansion" stuff is equal to "gz" (Those gzip compressed log files). The expression ${1##*.} means that if the pattern "*." matches the beginning of our parameter "$1" (ie: "/var/log/cron/errors.3.gz"), then the longest "##" matching pattern is deleted (all the stuff including the last "."), so then returning just the string "gz". if the conditional construct returns true, then the block of code after the "&&" (and) is executed: Code: rm $1 That means deletion of *.gz But if the conditional construct returns false, meaning that the file is not a gzip compressed log file, then the block of code after the "||" (or) is executed: Code: (tail -50 $1 > ${1}.tmp && cat ${1}.tmp > $1 && rm ${1}.tmp) I've put the code between ( ) to avoid problems of interpretation. That block of code means: tail -50 $1 > ${1}.tmp # Save the last 50 lines of $1 to a temporary file named $1.tmp; ie: tail -50 /var/log/messages > /var/log/messages.tmp If that is achieved without error (&&), then: cat ${1}.tmp > $1 && rm ${1}.tmp # overwrite the original file with the contents of the temporary one and finally delete the temporary file. Again, and again: UNIX (GNU/Linux) is so cool!!! joehill Senior user Joined: 09 May 2002 Posts: 217 Location: Toronto, Canada Post Posted: Wed Oct 16, 2002 7:35 pm Post subject: _________________________________________________________________ you are a freaking genius. really. arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Thu Oct 17, 2002 9:16 am Post subject: _________________________________________________________________ Embarassed well, thanks, I'm just a bash junkie ( need bash to live!!! ) joehill Senior user Joined: 09 May 2002 Posts: 217 Location: Toronto, Canada Post Posted: Thu Oct 17, 2002 11:35 am Post subject: _________________________________________________________________ genius, junkie, same thing... rolf Moderator Joined: 16 Apr 2002 Posts: 968 Location: Oakland, CA USA Post Posted: Tue Nov 12, 2002 1:16 am Post subject: a tribute to this thread _________________________________________________________________ Thanks, all, especially arusabal. I had this thread in the back of my mind until today, when, after substantial perusal of bash resources, the answer was revealed in the use of function. What I wanted to do was create an alias for a command line using this neato script for printing addresses, including my return address, on envelopes, giving only a text file containing the 'To' address as argument to: /home/rolf/envelope/envelope <file> | lpr which prints out the envelope as configured in an .enveloperc file, including a bar code, which is handy for mailing invoices for my small handyman business. As we all know, I was not able to use a variable for the text file argument in an alias, despite lengthy trial and error. What is working is to put function e() { /home/rolf/envelope/envelope $1|lpr; } at the bottom of ~/.bashrc and I only have to do, in the directory containing my address files: e <file> to have the envelope printed out. Thanks for this helpful thread Smile arusabal Moderator Joined: 17 Apr 2002 Posts: 836 Location: Spain Post Posted: Tue Nov 12, 2002 5:22 pm Post subject: _________________________________________________________________ You are wellcome rolf Smile Editor's note: This thread was originally posted at the old MUB (Mandrake User Board at club-nihil). This post is the result of a 99% automatic backup, so due to its nature some text may be lost (improbable but possible). Quote Link to comment Share on other sites More sharing options...
Guest anon Posted March 31, 2004 Report Share Posted March 31, 2004 *Bump* Quote Link to comment Share on other sites More sharing options...
!nkubus Posted March 31, 2004 Report Share Posted March 31, 2004 i love the CDPATH on it's very usefull. all of the others are quite useful to :) thanks :) Quote Link to comment Share on other sites More sharing options...
aRTee Posted March 31, 2004 Report Share Posted March 31, 2004 Noticed the directory tricks; give this a try: when in a dir somewhere you realise you want to go back to the previous one: cd - Enjoy :P Quote Link to comment Share on other sites More sharing options...
Steve Scrimpshire Posted December 2, 2004 Report Share Posted December 2, 2004 root@laptop.home /home/omar 0005 02-Dec-04 > find /var/log -type f -exec "sh -c '[[ "${1##*.}" == "gz"]] && rm $1 || (tail -50 $1 > ${1}.tmp && cat ${1}.tmp > $1 && rm ${1}.tmp)' '{}' '{}';" find: missing argument to `-exec' What's wrong? Quote Link to comment Share on other sites More sharing options...
theYinYeti Posted December 2, 2004 Report Share Posted December 2, 2004 (edited) IMO, the command should end like that: '{}'" \; that is: remove the ; from inside the quotes, and add it escaped after them. Yves. Edited December 2, 2004 by theYinYeti Quote Link to comment Share on other sites More sharing options...
iphitus Posted December 2, 2004 Report Share Posted December 2, 2004 oooh awesomeage Quote Link to comment Share on other sites More sharing options...
aru Posted December 2, 2004 Author Report Share Posted December 2, 2004 (edited) theYinYeti is right. The command as it was originally posted was (from my own tricks repository folder): find /var/log -type f -exec sh -c '[[ "${1##*.}" == "gz" ]] && rm $1 || (tail -50 $1 > ${1}.tmp && cat ${1}.tmp > $1 && rm ${1}.tmp)' '{}' '{}' \; Editor's note: This thread was originally posted at the old MUB (Mandrake User Board at club-nihil). This post is the result of a 99% automatic backup, so due to its nature some text may be lost (improbable but possible). well it was not so improbable, was it? :? It looks like some special characters (such as \) in particular contex were lost Edited December 2, 2004 by aru Quote Link to comment Share on other sites More sharing options...
theYinYeti Posted December 2, 2004 Report Share Posted December 2, 2004 (edited) May I add this tip of mine: #!/bin/bash # $1 is the string to find # $2 is the string that will replace it eval sed '"s/'"$(sed -e 's/\([]\/*^$[]\)/\\\\\1/g' -e 's/"/\\"/g' <<<"$1")"'/'"$(sed -e 's/\([\/]\)/\\\\\1/g' -e 's/"/\\"/g' <<<"$2")"'/g"' Usage example: $ echo 'test "\(hello\)" [you] ^' | replace.sh '"\(hello\)"' "there's only \1 like" test there's only \1 like [you] ^ If you followed well, you understand that this script is a replacement script for strings, not regexp (as sed would normally do). Yves. Edited December 2, 2004 by theYinYeti Quote Link to comment Share on other sites More sharing options...
aru Posted December 2, 2004 Author Report Share Posted December 2, 2004 cool and twisted Quote Link to comment Share on other sites More sharing options...
adamw Posted December 2, 2004 Report Share Posted December 2, 2004 I just noticed something in the original (great) articles is out of date; it no longer needs to reference Cooker bash and external bash-completion, as both a bash that supports extended completion and a working bash-completion package are in stable Mandrake now. You can just 'urpmi bash-completion'. Could it perhaps be edited? Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.