Difference between revisions of "Bash"
(adds mime-report example) |
|||
(6 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | This article is a cheat sheet for things you learn to do in Bash (The Bourne Again Shell). | + | This article is a cheat sheet for things you learn to do in Bash (The Bourne Again Shell). |
== For Loops == | == For Loops == | ||
Line 14: | Line 14: | ||
<source lang="bash"> | <source lang="bash"> | ||
for i in `seq 1 10`; do echo "$i, "; done | for i in `seq 1 10`; do echo "$i, "; done | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</source> | </source> | ||
Line 111: | Line 68: | ||
== Using Find == | == Using Find == | ||
The find command in Linux is very powerful, and thus somewhat complex to learn all the syntax and options. | The find command in Linux is very powerful, and thus somewhat complex to learn all the syntax and options. | ||
− | Suffice to say that you can read the manpage and info pages to answer your questions. | + | Suffice to say that you can read the manpage and info pages to answer your questions. |
=== Mime report === | === Mime report === | ||
Line 130: | Line 87: | ||
Breakdown: | Breakdown: | ||
<pre> | <pre> | ||
− | |||
2. look for directories that are immediate descendants of the current directory | 2. look for directories that are immediate descendants of the current directory | ||
3. sort them | 3. sort them | ||
− | 4. don't include | + | 4. don't include hidden directories |
6. with these: echo the name of the directory as a 'heading' in the report | 6. with these: echo the name of the directory as a 'heading' in the report | ||
7. find the files per directory | 7. find the files per directory | ||
8. match only on the extensions found (between two and four-letter extensions) | 8. match only on the extensions found (between two and four-letter extensions) | ||
9. sort them | 9. sort them | ||
+ | </pre> | ||
10. count and summarize by unique values | 10. count and summarize by unique values | ||
− | |||
But it looks more impressive as a one-liner: | But it looks more impressive as a one-liner: | ||
Line 256: | Line 212: | ||
/proc | /proc | ||
/media/disk/backups | /media/disk/backups | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</source> | </source> | ||
Line 275: | Line 222: | ||
* [http://penguinpetes.com/b2evo/index.php?title=how_the_one_liner_for_loop_in_bash_goes Penguin Pete] | * [http://penguinpetes.com/b2evo/index.php?title=how_the_one_liner_for_loop_in_bash_goes Penguin Pete] | ||
* [[wp:Bash|Wikipedia page]] | * [[wp:Bash|Wikipedia page]] | ||
− | |||
[[Category:System Administration]] | [[Category:System Administration]] |
Revision as of 01:34, 21 February 2015
This article is a cheat sheet for things you learn to do in Bash (The Bourne Again Shell).
For Loops[edit | edit source]
The bash one-liner for doing a for loop looks something like this:
for FILE in $(ls); do [COMMAND]; done
Here is a real example that will lowercase the names of all files in the current directory:
for FILE in $(ls); do mv $FILE $(echo $FILE | tr [A-Z] [a-z]); done
To do simple range looping, use the seq command:
for i in `seq 1 10`; do echo "$i, "; done
If construct[edit | edit source]
The then
can go on the same line as the if
as long as you use a semi-colon to terminate the if clause. Alternately, you can put the then
on it's own line
if EXPR; then
# do stuff
fi
is equivalent to
if EXPR
then
# do stuff
fi
Adding an else
clause
if EXPR; then
# do stuff
else
# do other stuff
fi
Adding multiple else
clauses with elif; then
if EXPR; then
# do stuff
elif EXPR; then
# do other stuff
else
# final else
fi
Note: sometimes you want to comment out a section of an if/else block, or maybe it does nothing at all. In this case, you'll get an error. To avoid the error, you can use the bash built-in :
(colon command)
: [arguments]
Do nothing beyond expanding arguments and performing redirections. The return status is zero.
if [ -f "/tmp/Non-existing-file.txt" ] ; then
echo "I found the non-existing file"
else
: # the colon command prevents an error if there are no other statements in this block
fi
Using Find[edit | edit source]
The find command in Linux is very powerful, and thus somewhat complex to learn all the syntax and options. Suffice to say that you can read the manpage and info pages to answer your questions.
Mime report[edit | edit source]
This example finds and counts files by their extension. A "poor-man's mime-report"
1 for x in \
2 $(find . -maxdepth 1 -type d | \
3 sort | \
4 grep -v ^./$ ); \
5 do \
6 echo -e "\n\n$x\n"; \
7 find "$x" -type f | \
8 egrep -o '\.(.?.?..)$' | \
9 sort | \
10 uniq -c ; \
11 done
Breakdown:
2. look for directories that are immediate descendants of the current directory 3. sort them 4. don't include hidden directories 6. with these: echo the name of the directory as a 'heading' in the report 7. find the files per directory 8. match only on the extensions found (between two and four-letter extensions) 9. sort them
10. count and summarize by unique values
But it looks more impressive as a one-liner:
for x in $(find . -maxdepth 1 -type d|sort|grep -v ^./$); do echo -e "\n\n$x\n"; find "$x" -type f | egrep -o '\.(.?.?..)$' | sort | uniq -c ; done
Prune[edit | edit source]
In case you are trying to figure out the prune option so that you can efficiently scan a directory for something while also ignoring .svn metadata, here is an example:
find ./ -name .svn -prune -o -name "*html*"
Or, a more complex example: 'wcgrep', from the contrib section of the svn repo:
#!/bin/bash
# Copyright 2004 Ben Reser <ben@reser.org>
# Licensed under the terms subversion ships under or GPLv2.
# Useful for greping in a subversion working copy.
# Essentially it behaves the same way your grep command does (in fact it
# ultimately calls the grep command on your path) with a few exceptions.
# Ignores the subversion admin directories (.svn) and vi(m) backup files.
# Recursive is always on with or without -r.
# Always print filename and line numbers.
# Ignores binary files.
# If no path is given the current working directory is searched not stdin.
# Other than that it will take any parameter or pattern your standard grep
# does.
#
# This script requires GNU findutils and by default GNU grep (though that
# can be changed with environment variables).
#
# There are three environment variables you can set that modify the default
# behavior:
#
# WCGREP_GREP Controls what command is used for the grep command.
# If unset or null wcgrep will use the command named grep.
# WCGREP_GREPARGS Controls what arguments are always passed to the grep
# command before the arguments given on the command line.
# If unset or null it defaults to -HnI (always print file
# names, line numbers and ignore binary files). If you wish
# to set no default args set the variable to a space (" ").
# WCGREP_IGNORE Controls what files are ignored by the grep command.
# This is a regex that is passed to the find command with
# -regex so see find's man page for details. If unset or
# null defaults to '.*~$\|.*/\.svn\(/\|$\)', which will
# ignore vim backup files and subversion admin dirs.
arg_count=$#
for (( i=1; i <= $arg_count; i++ )); do
arg="$1"
shift 1
if [ -z "$pattern" ]; then
if [ "$arg" == "--" ]; then
grepargs="$grepargs $arg"
pattern="$1"
shift 1
((i++))
elif [ "${arg:0:1}" != "-" ]; then
pattern="$arg"
else
grepargs="$grepargs $arg"
fi
else
pathargs="$pathargs $arg"
fi
done
find $pathargs -regex ${WCGREP_IGNORE:-'.*~$\|.*/\.svn\(/\|$\)'} -prune -o \
-type f -print0 | xargs -r0 ${WCGREP_GREP:-grep} ${WCGREP_GREPARGS:--HnI} \
$grepargs "$pattern"
Examples[edit | edit source]
This script sets the svn:executable property on a number of files
#!/bin/bash
DIRECTORIES="./example.org/htdocs/
./www.example.org/htdocs/
./security.example.org/htdocs/
./insurance.example.org/htdocs/
./hr.example.org/htdocs/"
for DIRECTORY in $DIRECTORIES
do
echo
echo "working on $DIRECTORY";
for FILE in $(find $DIRECTORY -name .svn -prune -o -type f -regex '.*s?html$'|\
grep -v .svn | xargs grep -l '\-\-\#include');
do svn propset svn:executable ON $FILE;
# do ls $FILE;
done
echo "$DIRECTORY processing complete"
echo
done
echo
echo "Finished fixing websites"
echo
Sometimes when using find, you end up with "Permission denied" errors that add noise to your output. There are a couple solutions for this. Use the prune option to skip entire trees that you should avoid (e.g. /proc). Use shell redirection to ignore remaining error messages (e.g. 2>/dev/null).
The following example searches all of my hard drive starting at / but skips over the backups directory I have in my external disk drive and also skips over the "process" directory. Any errors like files in /var that I do not have permission to see are discarded by redirecting STDERR to the bitbucket.
find / -path /media/disk/backups -prune -o -path /proc -prune -o -type d -name soffice.cfg 2>/dev/null
/home/greg/.openoffice.org2/user/config/soffice.cfg
/home/greg/.openoffice/1.1.1/user/config/soffice.cfg
/home/greg/.openoffice.org/3/user/config/soffice.cfg
/home/greg/spidey2/.openoffice.org2/user/config/soffice.cfg
/home/greg/liberty/greg/.openoffice.org2/user/config/soffice.cfg
/home/greg/liberty/greg/.openoffice/1.1.1/user/config/soffice.cfg
/opt/openoffice.org/basis3.0/share/config/soffice.cfg
/usr/lib/openoffice/basis3.0/share/config/soffice.cfg
/proc
/media/disk/backups
Resources[edit | edit source]
- greycat (Greg Wooledge) Wiki http://mywiki.wooledge.org/EnglishFrontPage maintained by lhunath (Maarten Billemont)
- http://bash.cyberciti.biz/guide/Main_Page an excellent BASH and Linux wiki site
- http://wiki.bash-hackers.org/scripting/style
- Maarten Billemont's Bash Guide
- Bash Reference Manual
- Penguin Pete
- Wikipedia page