Moje skromne początki w astrofotografii.

Po zakupie Tamrona 70-300 mm f/4-f/5,6, który u mnie z racji używania matrycy APS-C pracuje z zakresem ogniskowych 105-450 mm i głębi ostrości f/6-f/8,4, postanowiłem skierować go w stronę nocnego nieba. Zacząłem od Księżyca:

Następnie poszukałem Jowisza i z wielkim zdziwieniem po paru próbach otrzymałem całkiem niezły obraz.

Zdjęcie przedstawia Jowisza wraz z czterema z jego księżyców – najprawdopodobniej Europa, Io, Ganimedes i Kalisto (niestety nie potrafię powiedzieć w jakiej kolejności). Przyznam, że jestem z tego zdjęcia bardzo zadowolony ponieważ nigdy nie sądziłem, że coś tak odległego można zaobserwować tak podstawowym sprzętem.

sedros_std_lib.bash 0.1.1.3

Postanowiłem udostępnić kilka funkcji, które wykorzystuję podczas pisania wszystkich swoich skryptów. Na razie są to trzy funkcje:

  1. logMessage – wypisywanie komunikatów diagnostycznych na stderr
  2. printHelp – wyświetlenie „about section”, czyli zakomentowanej sekcji, którą zawsze umieszczam na początku skryptu, służącej jako pomoc użytkownikowi
  3. printUsage – wyświetlanie poprawnego wywołania skryptu

Więcej informacji na stronie projektu i w kodzie źródłowym.

Z czasem będę rozbudowywał tę bibliotekę o nowe funkcje. Mam nadzieję, że okażą się one przydatne dla kogoś oprócz mnie.

JPEG z RAW

Ostatnio coraz bardziej próbuję się wgryzać w fotografowanie, więc włączyłem w aparacie zapisywanie zdjęć zarówno w formacie RAW jak i JPEG. Założenie było takie, że na kilkadziesiąt zrobionych zdjęć będę mógł kilka najlepszych „podrasować”, wywołując je z RAW, a jednocześnie nie będę musiał ręcznie wywoływać wszystkich – często przecież nawet te średnie jakościowo zdjęcia chce się zachować.
Podczas jednej z rozmów z bardziej zaawansowanym kolegą dowiedziałem się, że coś takiego nie ma sensu o tyle, że w plikach RAW zaszyty jest niewielki JPEG. Szybkie zerknięcie w EXIF i rzeczywiście jest tam „Jpg From Raw”. Tak więc wystarczy prosta pętla z wykorzystaniem exiftool, aby sprawnie utworzyć pliki JPG o jakości wystarczającej do swobodnego przeglądania ich na komputerze czy telefonie lub udostępnienia ich komuś (olbrzymią zaletą jest to, że pliki mają 0,8-2,5 MB zamiast 12-13):

$ for pic in *
> do
> exiftool -b -JpgFromRaw ${pic} > $(echo ${pic} | sed s/.NEF/_preview.jpg/)
> done

Dzięki Ł. za podpowiedź!

Znak „%” w crontabie.

Jeśli zastanawiasz się, dlaczego masz problem z poprawnym wykonywaniem przez crona poleceń zawierających znak procentu (%), to zapewne dlatego, że nie wiesz jeszcze, że jest on traktowany jako znak nowej linii. Aby go użyć musisz postawić przed nim backslash (\) zakazując w ten sposób specjalnego traktowania tego znaku.

To nie zadziała:
25 * * * * /bin/date +"%F %T"

Ale to już tak:
25 * * * * /bin/date +"\%F \%T"

man 5 crontab:

Szóste pole (reszta wiesza) określa polecenie, jaką należy wykonać. Cała część polecenia wiersza, aż do nowego wiersza lub znaku %, zostanie wykonana przez /bin/sh, lub przez inną powłokę, jaką podano w zmiennej SHELL pliku crona. Procenty w komendzie (%), o ile nie są chronione odwrotnymi ukośnikami (\), zostaną zamienione w znaki nowego wiersza, a wszelkie dane za pierwszym % zostaną przesłane na standardowe wejście polecenia. Nie da się podzielić pojedynczego polecenia na wiele wierszy, tak jak w powłoce można to zrobić kończąc wiersz „\”.

Kopiowanie danych między dwoma serwerami za pośrednictwem trzeciego.

Co zrobić gdy trzeba znaleźć sprytny sposób na skopiowanie większej ilości danych pomiędzy dwoma serwerami, które nie mają ze sobą bezpośredniej łączności? Można skorzystać z trzeciego serwera i wydać na nim następujące polecenie:

$ ssh remote_server_1 'sudo sh -c "cd /source/path && tar cpf - *"' | ssh remote_server_2 'sudo sh -c "cd /destination/path && tar xpf -"'

Polecenie to zostało wykonane na trzech systemach HP-UX, ale analogiczne można wykonać na systemach Linux.

Za jakiś czas postaram się napisać nieco bardziej szczegółowy wpis na temat kopiowania danych z wykorzystaniem ssh, tar i potoków.

Wyjątek RPC podczas wykonywania swcopy.

Pewnego razu podczas próby stworzenia z płyt instalacyjnych HP-UX depotu, napotkałem następujący problem:

# swcopy -x enforce_dependencies=FALSE -x reinstall=TRUE -x mount_all_filesystems=false -s /var/opt/ignite/iso/ \* @ /var/opt/ignite/depots/0314

ERROR:   RPC exception: "Connection request rejected (dce / rpc)"
09/05/14 11:44:09 EST
ERROR:   Could not perform the requested operation for
"server:/var/opt/ignite/depots/0314",
possibly due to a network communications failure or the agent
timing out. Check that the host is still accessible from the
network, and the agent_timeout_minutes option is not set too
low.

Po krótkich poszukiwaniach okazało się, że rozwiązanie jest bardzo proste. Wygląda na to, że paczek jest za dużo dla swcopy w związku z czym zadanie należy rozbić na kilka etapów. Ja na przykład podzieliłem pliki na te zaczynające się cyframi, małymi i wielkimi literami:

# swcopy -x enforce_dependencies=FALSE -x reinstall=TRUE -x mount_all_filesystems=false -s /var/opt/ignite/iso/ [0-9]\* @ /var/opt/ignite/depots/0314
# swcopy -x enforce_dependencies=FALSE -x reinstall=TRUE -x mount_all_filesystems=false -s /var/opt/ignite/iso/ [a-z]\* @ /var/opt/ignite/depots/0314
# swcopy -x enforce_dependencies=FALSE -x reinstall=TRUE -x mount_all_filesystems=false -s /var/opt/ignite/iso/ [A-Z]\* @ /var/opt/ignite/depots/0314

Sourcing psuje getopts w ksh88.

Jakiś czas temu natknąłem się na pewną ciekawostkę w powłoce Korna (ksh) w wersji 88. Okazuje się, że sourcowanie skryptu wraz z przekazaniem parametrów do niego wewnątrz innego skryptu przesłania parametry przekazywane do tego drugiego skryptu. Zobaczmy na przykładzie zrealizowanym w systemie AIX 7 (tak samo jest w HP-UX 11.31).

Zaczynamy od zwykłego skryptu, który będzie przyjmował opcje „-a” i „-b”:

#! /usr/bin/ksh

while getopts ab OPTION
do
  case $OPTION in
    a) print "AAA" ;;
    b) print "BBB" ;;
  esac
done

Uruchomienie go daje następujące rezultaty:
$ ./test.ksh
$ ./test.ksh -a
AAA
$ ./test.ksh -b
BBB
$

Tak więc gdy skrypt jest wywoływany bez parametrów nic się nie dzieje. W przypadku wywołania z opcją „-a” na ekranie zostaje wypisane „AAA”, w przypadku „-b” „BBB”. Jest to zgodne z naszymi oczekiwaniami.

Dodajmy sourcowanie skryptu source.ksh:

#! /usr/bin/ksh

. ./source.ksh

while getopts ab OPTION
do
  case $OPTION in
    a) print "AAA" ;;
    b) print "BBB" ;;
  esac
done

Treść source.ksh nie jest tu zbyt istotna – u mnie było to po prostu:

print "Sourced script!"

Wyniki uruchomień skryptu są następujące:
$ ./test.ksh
Sourced script!
$ ./test.ksh -a
Sourced script!
AAA
$ ./test.ksh -b
Sourced script!
BBB
$ ./test.ksh -ab
Sourced script!
AAA
BBB
$

Czyli jak na razie nic szczególnego się nie dzieje. Jedyna różnica w porównaniu z poprzednią wersją skryptu jest taka, że widać działanie sourcowanego skryptu – pojawia się napis „Sourced script!”.

Jednak co będzie gdy dodamy do wywołania source.ksh parametr?

#! /usr/bin/ksh

. ./source.ksh xyz

while getopts ab OPTION
do
  case $OPTION in
    a) print "AAA" ;;
    b) print "BBB" ;;
  esac
done

Wyniki wywołań są następujące:
$ ./test.ksh
Sourced script!
$ ./test.ksh -a
Sourced script!
$ ./test.ksh -b
Sourced script!
$ ./test.ksh -ab
Sourced script!
$

Za każdym razem wynik jest ten sam! Niezależnie od tego, czy wywołujemy test.ksh z opcjami czy nie, nie są one przetwarzane. Aby sprawdzić, co się dzieje, dodajmy na końcu test.ksh instrukcję wydrukowania pierwszego parametru pozycyjnego skryptu:

#! /usr/bin/ksh

. ./source.ksh xyz

while getopts ab OPTION
do
  case $OPTION in
    a) print "AAA" ;;
    b) print "BBB" ;;
  esac
done

print $1

Sprawdźmy:
$ ./test.ksh
Sourced script!
xyz
$ ./test.ksh -a
Sourced script!
xyz
$

Jak widać pierwszym parametrem pozycyjnym, zarówno podczas wywołania skryptu bez parametrów jak i z, jest parametr podany do source.ksh.

Sprawdźmy co będzie w przypadku zastosowania ksh93:

#! /usr/bin/ksh93

. ./source.ksh xyz

while getopts ab OPTION
do
  case $OPTION in
    a) print "AAA" ;;
    b) print "BBB" ;;
  esac
done

Sprawdźmy:
$ ./test.ksh
Sourced script!
$ ./test.ksh -a
Sourced script!
AAA
$ ./test.ksh -b
Sourced script!
BBB
$ ./test.ksh -ab
Sourced script!
AAA
BBB
$

Czyli zaobserwowany podczas używania ksh88 problem nie istnieje.

Porównajmy to z bashem (wersja 4.3.39). Mamy testowy skrypt test.bash:

#! /bin/bash

. ./source.bash xyz

while getopts ab OPTION
do
  case $OPTION in
    a) echo "AAA" ;;
    b) echo "BBB" ;;
  esac
done

Gdy wywołamy ten skrypt otrzymujemy:
$ ./test.bash -a
Sourced script!
AAA
$ ./test.bash -b
Sourced script!
BBB
$

A zatem wynik diametralnie inny niż w ksh88.

No dobrze. A co się dzieje w przypadku ksh93 dostępnego w Linuksie?

#! /bin/ksh

. ./source.ksh xyz

while getopts ab OPTION
do
  case $OPTION in
    a) print "AAA" ;;
    b) print "BBB" ;;
  esac
done

Otrzymujemy następujące wyniki:
$ ./test.ksh
Sourced script!
$ ./test.ksh -a
Sourced script!
AAA
$ ./test.ksh -b
Sourced script!
BBB
$

Wnioski? Należy pamiętać, że gdy chcemy skorzystać w ksh88 z getopts i jednocześnie przekazać parametry do sourcowanego skrytpu to getopts musi zostać wykorzystane wcześniej niż sourcowanie. Unikniemy w ten sposób przesłonięcia parametrów pozycyjnych głównego skryptu.

Zmiana wielkości primary swap w HP-UX.

Jakiś czas temu okazało się, że na jednym z moich serwerów popełniłem błąd podczas instalacji systemu i zamiast 64 GB swapu skonfigurowałem tylko 8. Dodatkowo należało utworzyć kolejne 64 GB drugorzędnej przestrzeni wymiany (czyli po angielsku „secondary swap”). Jak wykonać takie zadanie?

      1. Zacznijmy od sprawdzenia aktualnej konfiguracji grupy wolumenowej vg00 i pamieci swap, aby zweryfikować stan obecny:
        # vgdisplay -v vg00
        # swapinfo
        W moim przypadku potwierdziło się, że grupa vg00 składa się z 8 wolumenów logicznych, a lvol2, służący za przestrzeń wymiany, liczy sobie tylko 8 GB. Swapinfo potwierdziło, że jest to jedyny swap z jakiego korzysta system.
      2. Następnie utworzyłem wolumen logiczny na drugorzędny swap:
        # lvcreate -C y -L 65536 -n lvol9 /dev/vg00
        Wolumen logiczny pod przestrzeń wymiany musi być spójny, tak więc konieczne jest użycie opcji -C z argumentem y. Opcja -L pozwala nam podać wielkość wolumenu w MB. Dzięki opcji -n możemy zdefiniować nazwę wolumenu – ja nie byłem tu zbyt odkrywczy i skorzystałem ze standardowej konwencji nazewniczej HP-UX tworząc „lvol9”.
      3. Kolejnym krokiem jest włączenie swapowania na nowo utworzonym wolumenie:
        # swapon -p 2 /dev/vg00/lvol9
        Opcja -p jest konieczna do zdefiniowania priorytetu przestrzeni swap. Zdefiniowanie priorytetu innego niż jeden konieczne jest jeśli chcemy później bezproblemowo usunąć informacje o konfiguracji pierwszorzędnego swapu z konfiguracji grupy wolumenowej vg00.
      4. Aby podejrzeć czy poprawnie włączyliśmy swap możemy zerknąć na wynik polecenia:
        # swapinfo
        Na tym etapie jak usyskałem informację o dwóch przestrzeniach swap: lvol2 z priorytetem 1 i o wielkości 8 GB i lvol9 z priorytetem 2 i o wielkości 64 GB.
      5. Skoro miałem już dodatkową przestrzeń wymiany, którą mój dość mocno obciążony system mógł wykorzystać, mogłem wyłączyć swapowanie na lvol2:
        # swapoff /dev/vg00/lvol2
      6. Po raz kolejny sprawdziłem poprawoności wykonania poprzedniej operacji:
        # swapinfo
      7. Teraz możliwej już było usunięcie informacji o primary swap i urządzeniu przeznaczonym na dumpy (w moim przypadku również lvol2) z konfiguracji grupy wolumenowej vg00:
        # lvrmboot -s vg00
        # lvrmboot -d lvol2 /dev/vg00
        Bez wykonania powyższych operacji niemożliwe jest usunięcie lvol2.
      8. Wreszcie mogłem usunąć lvol2:
        # lvremove /dev/vg00/lvol2
      9. Kolejnym krokiem było ponowne utworzenie wolumenu lvol2 o nowej wielkości:
        # lvcreate -C y -r n -L 65536 -n lvol2 /dev/vg00
        Podobnie jak wcześniej podczas tworzenia lvol9 i teraz musimy użyć opcji -C z argumentem „y”. Wcześniej za to nie używaliśmy opcji -r, która w tym przypadku jest konieczna – wraz z argumentem „n” wyłącza relokację danych w przypadku wystąpienia bad blocków.
      10. Teraz należało dodać do konfiguracji vg00 informację o primary swap i urządzeniu przeznaczonym na dumpy:
        # lvlnboot -s /dev/vg00/lvol2
        # lvlnboot -d /dev/vg00/lvol2
        W przypadku niewykonania powyższych poleceń system po restarcie nie będzie wiedział, których urządzeń użyć do swapowania i zrzucania dumpów.
      11. Tak jak wcześniej sprawdziłem poprawność wykonanych przeze mnie operacji:
        # vgdisplay -v vg00
        # lvdisplay /dev/vg00/lvol2
      12. Teraz mogłem już aktywować swap na lvol2:
        # swapon -p 1 /dev/vg00/lvol2
        Użyłem opcji -p 1 ponieważ chciałem aby był to primary swap.
      13. Sprawdziłem czy wszystko poszło jak planowałem:
        # swapinfo
        Wynik polecenia mówił, że mam teraz dwa urządzenia, na których zachodzi swapowanie: lvol2 i lvol9 – oba mające po 64 GB wielkości.
      14. Na koniec pozostało dodanie informacji o drugorzędnym urządzeniu swap do fstab:
        # vi /etc/fstab
        Na końcu pliku konieczne było dodanie linii:
        /dev/vg00/lvol9 / swap pri=2 0 0
        Znak „/”, który widzisz w drugim polu, może być zastąpiony „.” (aktualny katalog) lub dowolną inną ścieżką – nie jest to dla systemu istotne.

Pamiętaj aby wszystkie powyższe komendy znajdują się w /usr/sbin, a wykonywać należy je z konta roota lub poprzez sudo.

No i proszę – wszystko naprawione. Można brać się za realizację innych zadań.


Użyteczne zasoby: