Forum Linux.pl

Programowanie => Bash, skrypty powłoki => Wątek zaczęty przez: www0_0 w 2021-02-22, 00:12:09

Tytuł: 3 skrypty bash prośba o pomoc
Wiadomość wysłana przez: www0_0 w 2021-02-22, 00:12:09
Witam
Zwracam się do was forumowicze z prośbą o pomoc.
Na zaliczenie kolokwium dostałem takie zadanie:
Cytuj
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.
Tytuł: Odp: 3 skrypty bash prośba o pomoc
Wiadomość wysłana przez: Paweł Kraszewski w 2021-02-22, 07:54:38
#1/3 Polecenie find (https://www.linux.pl/man/index.php?command=find) z odpowiednimi parametrami plus polecenie wc udzielą potrzebnej odpowiedzi.
#3 Linijki o których piszesz to nie regexpy a podstawianie zmiennych (https://tldp.org/LDP/abs/html/parameter-substitution.html). Może ten tekst coś rozjaśni.

Co do błędów:

* Zainstaluj sobie VSCode (https://code.visualstudio.com/) (matko, do czego doszło, polecam soft od Microsoftu). W nim zainstaluj metapakiet lizebang.bash-extension-pack . To powinno pomóc przy pisaniu i sprawdzaniu skryptów. Po zainstalowaniu podpowie, jakie dodatkowe pakiety doinstalować do pełnej funkcjonalności. Twój najlepszy przyjaciel to będzie zakładka "problems" pod edytorem.

*  Na szybko: w find fragmenty \;#Blabla oraz \; #Blabla są inaczej interpretowane - znajdź różnicę. Poprawny jest drugi zapis.

* Zawsze umieszczaj zmienne w cudzysłowach, zwłaszcza te pochodzące od użytkownika.
Tytuł: Odp: 3 skrypty bash prośba o pomoc
Wiadomość wysłana przez: 1709 w 2021-02-22, 15:06:30
Na linuxie można używać shellcheck. To narzędzie do analizowania skryptów.
" Podpowiada " gdzie można łatwiej znaleźć np. brakującego cudzysłowia lub gdzie go lepiej użyć.



Wiem że to trudne, bo nie zadaje się pytań, jeśli nie zna się problemów.
Ale swoją drogą jeśli jest to możliwe to zadawaj nauczycielowi jak najwięcej pytań, bo to on powinien uczyć.
Bo tak to już jest, że nauczyciel czasami nie informuje że można się go spytać. Uczeń nie pyta.
A potem zamiast następnej lekcji jest godzina wyjaśniania problemów z zadania domowego.
I to nie u każdego, bo niektórzy "szanują" swój czas. Więc potem trzeba sobie radzić samemu z zaległościami w nauce.

Tytuł: Odp: 3 skrypty bash prośba o pomoc
Wiadomość wysłana przez: Paweł Kraszewski w 2021-02-22, 16:29:31
Cytuj
Na linuxie można używać shellcheck. To narzędzie do analizowania skryptów.
" Podpowiada " gdzie można łatwiej znaleźć np. brakującego cudzysłowia lub gdzie go lepiej użyć.

Jednym z pluginów, które instaluje wspomniany przeze mnie metapakiet jest m.in. obsługa shellcheck-a. ;)
Tytuł: Odp: 3 skrypty bash prośba o pomoc
Wiadomość wysłana przez: www0_0 w 2021-02-23, 20:05:59
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 ??
Tytuł: Odp: 3 skrypty bash prośba o pomoc
Wiadomość wysłana przez: Paweł Kraszewski w 2021-02-23, 21:08:02
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
Tytuł: Odp: 3 skrypty bash prośba o pomoc
Wiadomość wysłana przez: www0_0 w 2021-02-23, 22:24:14
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
set -x

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.
Tytuł: Odp: 3 skrypty bash prośba o pomoc
Wiadomość wysłana przez: Paweł Kraszewski w 2021-02-24, 07:02:58
Glad to help.

Przy takim robieniu zadań domowych możemy pomagać: pytający miał większość zrobioną, tylko małe problemy techniczne i niewielkie luki w wiedzy.

Na innym portalu "pomocowym" standardem jest po prostu wklejenie polecenia zadania domowego (i jest szczęście, jak jest cała treść i nieprzekręcone wyrazy) i "człowiek pomusz". Co prawda jest to miecz obosieczny, bo czasami wymagany język programowania nie jest częścią pytania (bo - dla pytającego - jest oczywisty, w końcu przekleił to z "1000 pytań z C++") i są odpowiedzi (zawsze poprawne i działające) w językach mocno niszowych (ja czasem wrzucam w Erlangu, ale bywają w Haskellu, APL, raz było nawet coś napisane w Cobolu.
Nawet jak język się zgadza (przypadkiem albo nie), to sposób rozwiązania jest absolutnie nie tym, czego chciał nauczyciel (pośrednia nauczka, żeby zadawać właściwe pytania).  Na zasadzie "napisz program wyświetlający liczby pierwsze z zakresu do 10" i ktoś wkleja (absolutnie technicznie poprawną) odpowiedź  print "2 3 5 7".
Najwyższy poziom jest, jak zadanie ma postać "napisz program w Assemblerze" i pytający zapomni podać architektury i systemu operacyjnego. Jest user odpowiadający na takie pytania programami na PDP11 :)
Wszystkie te kwiatki są zebrane razem w grupie "Trolling Homework (https://www.quora.com/q/trollingthehomework)".

P.S. W Indiach dzisiaj do nauki programowania używa się ciągle jeszcze TurboC (który powstał przed pierwszym oficjalnym standardem C++) i ludki piszą programy pod DOS. Nagłówki "graphics.h" i "conio.h" i płacz "why my program no compile on windows" to standard.
Tytuł: Odp: 3 skrypty bash prośba o pomoc
Wiadomość wysłana przez: www0_0 w 2021-02-25, 00:10:49
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:
Cytuj
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
gzip archiwum.tar
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
Cytuj
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
tar -uf
ale to nie obsługuje kompresji czyli
tar -uzf
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ą
diff 
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 :)
Tytuł: Odp: 3 skrypty bash prośba o pomoc
Wiadomość wysłana przez: Paweł Kraszewski w 2021-02-25, 06:57:19
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ą?
Tytuł: Odp: 3 skrypty bash prośba o pomoc
Wiadomość wysłana przez: 1709 w 2021-02-25, 14:23:45
Wydaje mi się że jest odrobinę nie precyzyjnie napisane zadanie.
Ponieważ nie jest napisane ogólnie jak skrypt lub komenda ma sprawdzać czy pliki się zmieniły.
Potrzebujemy jakiegoś wzorca katalogu do porównania z oryginałem.

1. Mogę przyjąć że skrypt jest uruchamiany codziennie o różnych godzinach
Archiwum mogło być zrobione wczoraj, a edytowany plik mógł powstać godzinę temu.

A) - Wzorcem może być katalog wewnątrz archiwum.
Tar ma opcje wyświetlenia zawartości archiwum z datą i tą datę można porównać np. z wyjściem ls -l
( comm bylby lepszą opcją (poleceniem) niż diff )
Ale wydaje mi się to zbyt skomplikowane, a można prościej.

B) - Wzorcem może być data utworzenia archiwum ( można od tej daty także odjąć przybliżony czas utworzenia archiwum - ale tego w zadaniu nie ma i to taka moja fanaberia )
Czyli jeśli są nowsze pliki niż owa data wtedy archiwizuj.

2. Mogę przyjąć także że godzina uruchamiania skryptu jest stała i wynosi 24 godziny.
Wtedy do pierwszego 1. twojego punktu zadania dodajesz tylko komunikat jeśli nie powstało nowe archiwum.
Lub inaczej,
jeśli nie ma plików do zarchiwizowania (wynosi 0),
   więc informacja że nie ma nowych plików i archiwum nie powstanie.
W innym przypadku ma być utworzone archiwum.


Dla pewności lepiej spytać swojego wykładowcę.


PS: Nowy problem = nowy temat.