Witam
Zwracam się do was forumowicze z prośbą o pomoc.
Na zaliczenie kolokwium dostałem takie zadanie:
Zadanie za 2 pkt
Utworzyć skrypt archiwum.sh:
1. Zarchiwizuj wszystkie pliki z drzewa katalogu domowego (/home/nazwa-usera), które zostały
zmodyfikowane w ciągu ostatnich 24 godzin.
2. Plik archiwalny ma być spakowany do tar.gz.
3. Skrypt ma sprawdzać czy jakieś pliki się zmieniły. Jeżeli żadnego nie ma to ma wypisać
komunikat, a jeżeli są to zarchiwizować do pliku.
4. Nazwa pliku archiwalnego ma być zadana przez użytkownika jako parametr skryptu.
Zadanie za 2 pkt
Utworzyć skrypt kosz.sh:
1. Wykonujący kopię pliku przed usunięciem (nie używaj w nazwach * i ?).
2. Skrypt pobierze tylko jeden argument w wierszu poleceń. Wypisuje komunikat o błędzie,
jeśli nie podano żadnego argumentu lub więcej niż jeden argument.
3. Utwórzy katalog .kosz w bieżącym katalogu, jeśli nie został jeszcze utworzony.
4. Skopiuje plik wskazany przez pierwszy argument do .kosz.
5. Usunie podany plik w bieżącym katalogu roboczym.
Zadanie za 1 pkt
Opisać skrypt z załączonego listingu.
1. Napisać do czego służy skrypt i podać 3 przykłady jego wywołania
2. Uzupełnić wszystkie puste polecenia echo wpisując odpowiednie komentarze
3. Dodać komentarz opisujący co się dzieje w blokach (warunkowych, pętlach czy funkcjach)
1 #!/ bin/ bash
2 valid ()
3 {
4 var1 ="$1"; var2 ="$2"; var3 ="$3"
5
6 if [ -z $var1 ] ; then
7 echo " " >&2 ; return 1
8 fi
9
10 if [ "${ var1 %${ var1 #?}} " = "-" ] ; then
11 test ="${ var1 #?} "
12 else
13 test =" $var1 "
14 fi
15
16 result ="$( echo $test | sed ’s /[[: digit :]]//g ’)"
17
18 if [ ! -z $result ] ; then
19 echo " " >&2
20 return 1
21 fi
22
23 if [ ! -z $var2 ] ; then
24 if [ " $var1 " - lt " $var2 " ] ; then
25 echo "" >&2
26 return 1
27 fi
28 fi
29
30 if [ ! -z $var3 ] ; then
31 if [ " $var1 " - gt " $var3 " ] ; then
32 echo " " >&2
33 return 1
34 fi
35 fi
36
37 return 0
38 }
39
40 if valid "$1" "$2" "$3" ; then
41 echo " "
42 fi
I teraz tak po kilku godzinach udało mi się stworzyć w pełni działający skrypt kosz.sh
w skrypcie archiwum.sh udało mi sie opanować rzeczy zaznaczone podkreśleniem, jednak napotkałem pewne problemy dalej.
Spróbowałem skrypt napisać w taki sposób:
#!/bin/bash
# archiwum
a=$1
zmienna=$#
if [ $zmienna = 1 ]
then
if [ -e $a.tar.gz ] ; then #Sprawdzam czy istnieje archiwum z nazwą podaną w parametrze
echo "Archiwum $a.tar.gz istnieje "
mkdir aktualne #tworze katalog aktualne na potrzeby skryptu
find /home/user -type f -mtime -1 -exec mv {} ~/aktualne \; #Wyszukuje pliki w katalogu domowym które w ostatnich 24 godzina były modyfikowane a następnie przenosze je do katologu aktualne
tar -uvf $a.tar.gz aktualne #pakuje katalog aktualne do arhiwum tar.gz o nazwie parametru
find /home/user/aktualne -type f -mtime -1 -exec mv {} ~ \;#Przenosze pliki z powrotem do katalogu domowego
rm -rf aktualne #usuwam katalog aktualne stworzony na potrzeby skryptu.
else
echo "Tworze nowe archiwum o nazwie $a.tar.gz"
mkdir aktualne #tworze katalog aktualne na potrzeby skryptu
find /home/user -type f -mtime -1 -exec mv {} ~/aktualne \; #Wyszukuje pliki w katalogu domowym które w ostatnich 24 godzina były modyfikowane a następnie przenosze je do katologu aktualne
tar -czvf $a.tar.gz aktualne #pakuje katalog aktualne do arhiwum tar.gz o nazwie parametru
find /home/user/aktualne -type f -mtime -1 -exec mv {} ~ \;#Przenosze pliki z powrotem do katalogu domowego
rm -rf aktualne #usuwam katalog aktualne stworzony na potrzeby skryptu.
fi
else
echo "Wywołaj skrypt jeszcze raz podając nazwe archiwum w pierwszym parametrze."
fi
aby zachować parametr z datą i godziną modyfikacji. Niestety sposób ten wywala wiele błędów. Natomiast jak wykonuje kopiowanie plików to tracę parametr daty, gdyż po skopiowaniu to już są zupełnie nowe pliki z datą i godziną w momencie kopiowania.
Myślę teraz aby wykonać to z koncepcji zapisywania wyników polecenia find do pliku, a następnie pakowania plików odczytując je z pliku. ale nie bardzo wiem jak listę wyników z find przesłać do pliku.
No i w tym trzecim zadaniu już wiem że pierwszy if odpowiada za sprawdzanie czy skrypt odpaliłem z pierwszym parametrem.
natomiast pokonały mnie wyrażenia regularne z lini 10,11 i 16 przez to nie bardzo wiem jak jeszcze można odpalić skrypt i co dokładnie ma robić.
obecnie opanowałem go w takim stopniu:
#!/bin/bash
valid()
{
var1="$1"; var2="$2"; var3="$3"
if [ -z $var1 ] ; then #Sprawdzamy czy istnieje pierwszy parametr skryptu
echo "Skrypt wywołany bez parametrów" >&2 ; return 1
fi
if [ "${var1%${var1#?}}" = "-" ] ; then
test="${var1#?}"
else
test="$var1"
fi
result="$(echo $test | sed ’s/[[:digit:]]//g’)"
if [ ! -z $result ] ; then
echo "Odpowiedz po drógim IF " >&2
return 1
fi
if [ ! -z $var2 ] ; then
if [ "$var1" -lt "$var2" ] ; then #Porównanie czy parametr 1 jest mniejszy od paramertu 2
echo "Pierwszy parametr jest mniejszy od drógiego parametru" >&2
return 1
fi
fi
if [ ! -z $var3 ] ; then
if [ "$var1" -gt "$var3" ] ; then # Porównanie czy parametr 1 jest większy od parametru 3
echo " Odpowiedz po czwartm IF" >&2
return 1
fi
fi
return 0
}
if valid "$1" "$2" "$3" ; then
echo "Skrypt zakończył działanie z spełnioną funkcjią valid "
fi
Dziękuje za jakiekolwiek wskazówki które naprowadzą mnie na rozwiązanie moich problemów.
Panowie to takie pytanko jeszcze na szybko bo nie mogę pojąć co jest nie tak z tą linią:
result="$(echo $test | sed ’s/[[:digit:]]//g’)"
wywołuje skrypt przez
./skrypt.sh 1k
i spodziewam się że w tej lini sed podmieni mi 1 na pusty znak. Bynajmniej ja to tak rozumiem.
Natomiast po takim wywołaniu dostaje taką odpowiedz:
sed: -e expression #1, char 1: unknown command:
i zupełnie jej nie rozumiem dlaczego ??
Jeżeli robiłeś przeklejkę z jakiejś strony albo PDF-a, to tam są sknocone cudzysłowy. Zwróć uwagę, ze sed jest u Ciebie w jakiś porypanych unikodowych apostrofach (chyba któryś z drukarskich). Powinien być w zwykłych apostrofach z klawisza koło Entera.
Hint: jako drugą linijkę swojego skryptu daj polecenie set -x:
#!/bin/bash
set -x
# reszta skryptu
Dodanie tej linijki sprawi, że skrypt będzie się "drukował" w trakcie wykonania, z rozwijaniem wszystkich zmiennych po drodze. Liczba plusów na początku linijki to poziom zagnieżdżenia popowłok, np konstrukcja $(polecenie) to właśnie podpowłoka.
Dla przykładu:
> cat te.sh
#!/bin/bash
set -x
test=t10a
result="$(echo $test | sed 's/[[:digit:]]//g')"
> ./te.sh
+ test=t10a
++ echo t10a
++ sed 's/[[:digit:]]//g'
+ result=ta
Dziękuje bardzo.
Faktem było że kopiowałem to z PDF a poprawiając na tak jak pan zaprezentował od razu zaczęło działać.
Natomiast polecenie
to od dziś moje ulubione polecenie. Z nim pisanie skryptów i ich analizowanie zrobiło się znacznie przyjemniejsze:)
Jeszcze raz dziękuje za pomoc.
Dzięki państwu już wiem że finalnie miało to wyglądać tak:
#!/bin/bash
valid()
{
var1="$1"; var2="$2"; var3="$3"
if [ -z $var1 ] ; then #Sprawdzamy czy istnieje pierwszy parametr skryptu
echo "Skrypt wywołany bez parametrów" >&2 ; return 1
fi
if [ "${var1%${var1#?}}" = "-" ] ; then #Sprawdza czy w var1 pierwszy znak to - jesli
test="${var1#?}" #jeśli tak usuwa jeden znak - oraz zapisuje wartosc zmiennej var1 do zmiennej test
else
test="$var1" #jeśli nie występuje to przepisuje wartosc zmiennej var1 do zmiennej test
fi
result="$(echo $test | sed 's/[[:digit:]]//g')" #podmienia wszystkie cyfry na puste znaki w zmiennej test a następnie wynik tej operacji przypisuje do zmiennej result
if [ ! -z $result ] ; then #sprawdza czy zmienna result nie jest pusta
echo "Wprowadz jedynie cyfry w 1 parametrze" >&2
return 1 #na wyjscie funkcji wystawia wartosc 1 czyli fałsz
fi
if [ ! -z $var2 ] ; then #sprawdza czy zmienna var2 bue jest pusta
if [ "$var1" -lt "$var2" ] ; then #Porównanie czy parametr 1 jest mniejszy od paramertu 2
echo "$var2 Jest większy niż $var1" >&2
return 1 #na wyjscie funkcji wystawia wartosc 1 czyli fałsz
fi
fi
if [ ! -z $var3 ] ; then #sprawdza czy zmienna var2 bue jest pusta
if [ "$var1" -gt "$var3" ] ; then # Porównanie czy parametr 1 jest większy od parametru 3
echo "$var1 Jest Największą wartością" >&2
return 1 #na wyjscie funkcji wystawia wartosc 1 czyli fałsz
fi
fi
return 0 #na wyjscie funkcji wystawia wartosc 1 czyli prawda
}
if valid "$1" "$2" "$3" ; then
echo "$1 Jest Największą wartością" >&2
fi
No chyba że coś źle zrozumiałem z tego kodu.
Biorę się za moją zmorę czyli program archiwum. Jakoś chwilowo koncepcyjnie w nim utknąłem.
Ale pytania zacznę zadawać dopiero jak obmyślę w głowie algorytm jak by to miało działać zgodnie z tymi założeniami.
Jeszcze raz bardzo dziękuje za wskazówki i podpowiedzi.
Witam Ponownie
jednak z skryptem archiwizującym będę musiał się zwrócić do państwa z prośbą pomocy.
Tak kwestią porządkową treść zadania to:
Zadanie za 2 pkt
Utworzyć skrypt archiwum.sh:
1. Zarchiwizuj wszystkie pliki z drzewa katalogu domowego (/home/nazwa-usera), które zostały
zmodyfikowane w ciągu ostatnich 24 godzin.
2. Plik archiwalny ma być spakowany do tar.gz.
3. Skrypt ma sprawdzać czy jakieś pliki się zmieniły. Jeżeli żadnego nie ma to ma wypisać
komunikat, a jeżeli są to zarchiwizować do pliku.
4. Nazwa pliku archiwalnego ma być zadana przez użytkownika jako parametr skryptu.
i o ile z punktem pierwszym niema problemu:
find ~ -type f -mtime -1 -exec tar -cf archiwum.tar {} \+
sprawdzone działa. Troszke trzeba było się naszukać tej nieszczęsnej składni ale robi robotę człowiek jest dumny z siebie:)
punkt drugi to też bajka
lub prościej w jednej linie
find ~ -type f -mtime -1 -exec tar -czf archiwum.tar.gz {} \+
Znów jest radość z sukcesów.
teraz skoczmy na chwilkę do punktu 4
nazwa="$1"
find ~ -type f -mtime -1 -exec tar -czf "$nazwa".tar.gz {} \+
i znów pełen sukces.
no i docieramy do nieszczęsnego punktu
3. Skrypt ma sprawdzać czy jakieś pliki się zmieniły. Jeżeli żadnego nie ma to ma wypisać
komunikat, a jeżeli są to zarchiwizować do pliku.
tu oczywiście prosta komenda
if [ -e "$nazwa.tar.gz" ]; then
i już wiemy że archiwum istnieje. no ale teraz co tu dalej począć.
niby jest
ale to nie obsługuje kompresji czyli nie działa
a samo archiwum owszem aktualizuje pliki ale które już występują w archiwum. nie usuwa plików których już niema w katalogu źródłowym ani nie dodaje nowych plików
no i jeszcze przydało by się sprawdzić czy coś się nam zmieniło w archiwum aby poinformować użytkownika.
i ten punkt jest tak problematyczny że nie bardzo potrafię wymyśleć koncepcie na rozwiązanie go.
Próbowałem już z folderami tymczasowymi do rozpakowania zawartości i porównywania komendą ale ta porównuje tylko nazwy plików w folderach a nie ich parametry modyfikacji czy rozmiaru.
myślałem o sumie md5 ale tu też zabrnąłem w ślepy zakątek. no brak mi pomysłu jak się za to zabrać i z jakich poleceń skorzystać.
czy może państwo macie jakąś sugestie jak ugryźć ten problem. zapewne próbuje wyważyć otwarte już drzwi, ale klamki jakoś nie mogę znaleźć. ;)
Bardzo Dziękuje z góry za każde wskazanie kierunku :)
Patrzysz od du*y strony na problem :)
Wyciąg z man-a do find-a (polski man do tej opcji niestety słabo przetłumaczony):
-newer REFFILE
File was modified more recently than REFFILE. If REFFILE is a sym-
bolic link and the -H option or the -L option is in effect, the
modification time of the file it points to is always used.
Teraz zastanów się - pliki modyfikowane później niż co cię interesują?