2007-2009 Bash Scripting - Skrypty Bash

Zbiór przydatnych skryptów bash (i funkcji do użycia we własnych skryptach).

Wstęp

Tutaj notuję sobie różne skrypty i funkcje w języku bash.
Może kiedyś z tego się wykluje jakiś HowTo :).

Licencja

Źródeł na tej stronie można używać na dowolnej z licencji: LGPL, BSD, PublicDomain.

Podstawowe elementy konstrukcji skryptów

Nagówek

Na początku każdego skryptu należy umieścić:

#!/bin/bash

W kolejnych liniach , "#' oznacza iż dalsza część lini oznacza komentarz.

Lista parametrow

Pod zmienną $@ kryje się lista prametrów.
Ale uwaga jeżeli zawierają spację to przy użyciu:

list_params $@

parametry ze spacjami zostana rozbite na oddzielne.
Aby tego uniknąć trzeba ująć w cudzysłów t.j. {"$@"} (trochę tak jakbyśmy chcieli każdy z parametrów ująć w cudzysłów).

zip backup.zip "$@"

iterowanie po parametrach

Aby wkonac po wszystkich paramatrach polecenia jakies polecenie np. "echo" robimy:

while [ ! -z "$1" ]; do
    echo $1
    shift
done

Aby iterowac po tych elementach trójkami robimy:
#dopuki wartosc zwrocona przez shift jest prawda (tzn. "0")    
ok=0    
while [ $ok -ne 1 ]; do
    echo $1 $2 $3
    shift 3
    ok=$?
done

funkcje

liczby_dwucyfrowe_od_00_do $max

#!/bin/bash

function liczby_dwucyfrowe_od_00_do
{
    local max=$1
    for (( i=0; i<=$max; i++ )) ; do
        #leading zeros
        i2=$(( $i + 100 ))
        istr=${i2:1:2}
        echo $istr
    done
}

echo type max
read max
liczby_dwucyfrowe_od_00_do $max

Kiedy posiadamy w systemie program "seq"

function liczby_dwucyfrowe_od_00_do 
{
seq -f '%02.0f' 0 $1
}

ew. "od-do"

function liczby_dwucyfrowe_od_do 
{
seq -f '%02.0f' $1 $2
}

process_each_input_line_to_empty ( Przetwarzaj oddzielnie linie wejścia aż do pustej)

Przetwarzaj oddzielnie linie wejścia aż do pustej.

#Przetwarza kazda linie wejscia oddzielnie w petli - aż do pustej
function process_each_input_line_to_empty
{
  read inputline
  while [ ! -z "$inputline" ]; do
    echo '  ####  '$inputline'   ###   '
    read inputline
  done  
}

Przykład użycia: liczby_dwucyfrowe_od_00_do 33 | process_each_input_line

A jak chcemy użyć jakiegoś polecenia na każdym z wierszy wejściowych to możemy się wspomóc AWK:

find |  awk '{ system( "dirname \"" $0 "\"" ); }'

( Praktyczne użycie : zcat file_list_2007-10-23.txt.gz | grep -i amppz | awk '{ system( "dirname \"" $0 "\"" ); }' | uniq )

rename_to_fat_convention

Z czasem będzie rozbudowane. Narazie tam gdzie trzeba dla podanej listy plikow zamienia w nazwach ":" na ".".

function convert_file_names_to_fat_names
{
#dopuki wartosc zwrocona przez shift jest prawda (tzn. "0")    
ok=0    
while [ $ok -ne 1 ]; do
    oldfn=$1
    newfn=$( echo $oldfn | sed 's/:/./g' )
    if [ "$newfn" != "$oldfn" ]; then 
        mv -v "$oldfn" "$newfn"
        fi
    shift 1
    ok=$?
done
}

Przykład użycia

convert_file_names_to_fat_names *.jpg

gethtmltitle, geturltitle

gethtmltitle - pobiera tytuł strony html podanej na wejscie
geturltitle - pobiera tytuł strony html o podanym adresie

#gethtmltitle 
#input : html code
function gethtmltitle {
gawk ' BEGIN { FS="</body>"; RS="</html>" }
/<title>/ { 
$0=gensub("\n"," ","G"); 
print gensub("(.*)<title([^>]*)>([^<]*)(.*)", "\\3", "G" ); 
}
/<TITLE>/ { 
$0=gensub("\n"," ","G"); 
print gensub("(.*)<TITLE([^>]*)>([^<]*)(.*)", "\\3", "G" ); 
}'
}

#geturltitle url
function geturltitle {
wget -o /dev/null -O - "$1"   | gethtmltitle
}

Przykład użycia: geturltitle 'http://grzegorz.wierzowiecki.pl/'

Zobacz również: 2007-10 List html files by titles with Awk

dirmd5

Funkcja robi sume md5 dla zadanego katalogu i ja w nim umieszcza.
Dobre do uzycia w petli for po katalogach w katalogu.

function dirmd5 ()
{
    currpwd=$PWD;
    cd "$1";
    md5sum_make_for_directory . >/tmp/"$1".md5;
    mv /tmp/"$1".md5 ./;
    cd "$currpwd"
}

Ale w większości przypadków wystarcza
find -type f -exec md5sum -b "{}" \;

checkmd5

Sprawdza sume md5 danego katalogu.
Zaklada istnienie w katalogu pliku o tej samej nazwie z rozszerzeniem ".md5".

function checkmd5 ()
{
    currpwd=$PWD;
    cd "$1";
    md5sum -c "$1".md5;
    cd "$currpwd"
}

cut_extension

Followinh script cuts only 3-4 letter extensions:

function cut_extension(){
local A="$1";
if echo "$A" | grep "\.[^.0-9]\{3,4\}$" > /dev/null
then A="$(echo "$A" | sed 's/\(^.*\)\.[^.]*/\1/')"
fi
echo $A;
}

Based on : http://lists.freebsd.org/pipermail/freebsd-questions/2003-October/021729.html

cut_last_letters

Paramteres:

  • text
  • how many letters to cut from end
function cut_last_letters(){ echo ${1:0:${#1}-$2}; }

get_last_letters

Parameters:

  • text
  • how many letters to get from end
function get_last_letters(){ echo ${1:${#1}-$2:$2}; }

get_first_letters

Parameters:

  • text
  • how many letters to get from beginning
function get_first_letters(){ echo ${1:0:$2}; }

cut_first_letters

Parameters:

  • text
  • how many letters to cut from beginning
function cut_first_letters(){ echo ${1:0,$2}; }

random_number

Parameters:

  • from
  • to

Generates random number between "from" and "to"

function random_number(){
  local rv=`od -An -N4 -t u4 /dev/random`;
  echo $[ ($rv%($2-$1+1)) + $1 ];
}

(To make it faster to generate a lot of such numbers, use pseudo-random generator "urandom" instead of "random")

Size_Of_Contents_Of_Compressed_Archive

[[code]
case ‘get_last_letters "$filename" 3` in
.gz)
gzip -l "$filename" | awk ’{print $2}' | grep -v uncompressed
;;
.7z)
7za -slt l "$filename" | grep '^Size =' | awk '{print $3}'
;;
esac
[[/code]]
Checks size of contents of archive in bytes

remove_extension

function remove_extension() {
sed 's/\(.*\)\..*/\1/'
}

misc

"Indirect References to Variables"

Taken from Advanced Bash Shell Scripting Guide - Indirect References to Variables.

Assume that the value of a variable is the name of a second variable. Is it somehow possible to retrieve the value of this second variable from the first one? For example, if a=letter_of_alphabet and letter_of_alphabet=z, can a reference to a return z? This can indeed be done, and it is called an indirect reference. It uses the unusual eval var1=\$$var2 notation.

a=letter_of_alphabet   # Variable "a" holds the name of another variable.
letter_of_alphabet=z

echo

# Direct reference.
echo "a = $a"          # a = letter_of_alphabet

# Indirect reference.
eval a=\$$a
echo "Now a = $a"      # Now a = z

My (Grzegorz's) example :) :

x=5
v=x
eval echo \$$v

funkcje - przykłady dłuższych

intersection_of_files_lines()

Want to find lines in files that have in common? Use this:

#params: file1 file2 [file3 [file4 ... ] ]
#output: lines that are in common
function intersection_of_files_lines(){
    if [ "$#" -eq 1 ]; then
        sort -u "$1"
    elif [ "$#" -eq 2 ]; then
        (sort -u "$1";sort -u "$b")|sort|uniq -d
    elif [ "$#" -ge 3 ]; then
        local a="$1"
        local b="$2"
        shift 2
        # make intersection of $a and $b. Then call again for intersection with rest.
        intersection_of_files_lines <( (sort -u "$a";sort -u "$b")|sort|uniq -d) "$@"
    fi
}

md5sum_make_for_stdin

Link : make_md5sum_for_directory.sh .

Skrypty / przykładowe użycia

Zamiania nazw plików na duże litery

Cel: zamiana nazw plików wykładXX.html na WYKADXX.html .
1. Zamiana z wykladXX.html na x_WYKADXX.HTML
for f in wyklad*.html ; do nf=$( echo $f | sed 's/.*/x_\U&/g' ); mv -v "$f" "$nf" ; done
2. Zamiana z x_WYKADXX.HTML na WYKADXX.html
@@++ Lista parametrow
Pod zmienną {{$@
kryje się lista prametrów.
Ale uwaga jeżeli zawierają spację to przy użyciu:

list_params $@

parametry ze spacjami zostana rozbite na oddzielne.
Aby tego uniknąć trzeba ująć w cudzysłów t.j. {"$@"} (trochę tak jakbyśmy chcieli każdy z parametrów ująć w cudzysłów).

zip backup.zip "$@"

iterowanie po parametrach

Aby wkonac po wszystkich paramatrach polecenia jakies polecenie np. "echo" robimy:

while [ ! -z "$1" ]; do
    echo $1
    shift
done

Aby iterowac po tych elementach trójkami robimy:
#dopuki wartosc zwrocona przez shift jest prawda (tzn. "0")    
ok=0    
while [ $ok -ne 1 ]; do
    echo $1 $2 $3
    shift 3
    ok=$?
done
O ile nie zaznaczono inaczej, treść tej strony objęta jest licencją Creative Commons Attribution-ShareAlike 3.0 License