These notes are not complete instructions for these commands, but are observations and hints. There are links to the Open Group's Single Unix Specification man pages.
Strip directory and optional suffix from filenames
With POSIX shells (ksh, bash, ash, etc.), there is no need for the (external) basename command.
To extract the filename from a path, you can use parameter expansion:
path=/home/user/filename.txt
echo ${path##*/}
To remove a suffix:
echo ${path%.txt}
To do both:
path=/home/user/filename.txt
base=${path##*/}
echo ${base%.txt}
The following function is a POSIX-compliant version of basename that uses no external commands:
basename()
{
_basename "$@" &&
printf "%s\n" "$_BASENAME"
}
_basename() ##
{
[ "$1" = "--" ] && shift
fn_path=$1
fn_suffix=$2
case $fn_path in
## The spec says: "If string is a null string, it is
## unspecified whether the resulting string is '.' or a
## null string. This implementation returns a null string
"") return ;;
*) ## strip trailing slashes
while :
do
case $fn_path in
*/) fn_path=${fn_path%/} ;;
*) break ;;
esac
done
case $fn_path in
"") fn_path="/" ;;
*) fn_path=${fn_path##*/} ;;
esac
;;
esac
case $fn_path in
$fn_suffix | "/" ) _BASENAME="$fn_path" ;;
*) _BASENAME=${fn_path%$fn_suffix}
esac
}
Strip last component from file path
With POSIX shells (ksh, bash, ash, etc.), there is no need for the dirname command.
To strip the filename from a path, you can use parameter expansion:
path=/home/user/filename.txt
echo ${path%/*}
The following function is a POSIX-compliant version of dirname that uses no external commands:
dirname()
{
_dirname "$1" && printf "%s\n" "$_DIRNAME"
}
_dirname()
{
[ "$1" = "--" ] && shift
_DIRNAME=$1;
strip_trailing_slashes;
case $_DIRNAME in
"")
_DIRNAME='/'
return
;;
*/*)
_DIRNAME="${_DIRNAME%/*}"
;;
*)
_DIRNAME='.'
;;
esac;
strip_trailing_slashes;
}
strip_trailing_slashes()
{
while :
do
case $_DIRNAME in
*/) _DIRNAME=${_DIRNAME%/} ;;
*) break ;;
esac
done
}
ed is a line-oriented text editor. It is used to create, display, modify and otherwise manipulate text files.
Use ed with caution.
Actually, use all commands with caution, but I single out ed because, unlike most Unix commands, it operates on files in situ.
Most commands (sed, awk, tr, head, tail, cat, etc.) send the output to stdout, which is usually the terminal or a file. When sent to a file, the output must be sent to a file other than the one being used for input (unless you append the output to the file, which is rarely what you would want).
The output file can then be moved over the original file. When testing the script, you can omit the replacement of the original file to check that the script has done what you want. Or you can back up the file before it is overwritten (if you are using GNU mv, just use the -b option).
Grep searches the named input FILEs (or standard input if no files are named, or the file name "-" is given) for lines containing a match to the given PATTERN.
Grep is good for searching files, but not a good tool for finding out whether one string is contained within another.
Rather than using:
echo "$string1" | grep "$string2" > /dev/null
a case statement can do the job without calling an external command:
case $string1 in
*$string2*) ;;
*) false ;;
esac
Print line, word, and byte counts for each FILE, and a total line if more than one FILE is specified. With no FILE, or when FILE is -, read standard input.
Options -c -w and -l specify whether to print the count of one or more of characters, words, or lines. If no option is given, all three are printed.
If you want to use the output of wc in a calculation, redirect or pipe
the file[s] into the command, and store the output in a variable:
lines=`wc -l < FILE` lines=`cat *.txt | wc -l`
Some versions of wc will put spaces before the output,
and this can cause problems. The spaces can be
removed by enclosing the result in an arithmetic expression:
lines=$(( `wc -l < FILE` )) lines=$(( `cat *.txt | wc -l` ))
Or you can set the results into the positional parameters, which has the advantage of removing any whitespace, as well as giving you the word count and character count if you want them:
set -- `wc FILE` lines=$1 words=$2 chars=$3 set -- `cat *.txt | wc` lines=$1 words=$2 chars=$3