convert из пакета imagemagick не центровал картинку на A4 pdf

А с картинкой из моего сканера точно такого же размера не работало. Содержимое картинки куда-то улетало за пределы страницы.
Если же использовалась опция -extent то всё работало, но картинка растягивалась до размеров страницы A4 и файл становился большего размера чем возможно: pdf – 213275 байта (картинка 98738), а добился я размера pdf 110868

Вот этот скрип даёт нужный результат (картинка в центре страницы PDF файла) но файл получается больше чем нужно.

$ convert -page 2480x3508 -units PixelsPerInch -density 300x300 -extent 2480x3508 \( -gravity center 2015.06.09.jpg \) -format pdf out.pdf

Continue reading convert из пакета imagemagick не центровал картинку на A4 pdf

bash script для запуска vncviewer на выбранную из списка виртуалку

Этот баш-скрипт я написал так как был недоволен утилитой Virtual Machine Manager которая имеет ошибку и не поддерживает у меня соединения через ssh туннель и её нужно патчить после каждого обновления. Но главное, что меня раздражает это тормоза работы Virtual Machine Manager так как он получает много зачастую ненужной информации от всех виртуальных машин. Данный скрипт работает сравнительно быстро потому, что запрашивает на сервере только самое необходимое, а именно список запущенных машин и смещение vnc порта для каждой.

#!/bin/bash

  # bash script to connect to virtual machine vnc port (over ssh tunnel)
  # баш скрипт выводит список виртуальных машин и предлагает выбрать с какой соединиться по VNC

function GETVNCPORTS {
  NODE=$1
  echo -e "Reading info from \"${NODE}\"" >&2
  awk -v node="${NODE}" '{print node" "$0}' < <(ssh -T "root@${NODE}" <<'END'
while read -r DOMAIN ; do PORT=`virsh vncdisplay "${DOMAIN}" | sed -e '/^[ \t]*$/d' | awk -F: '{printf "59%02d\n",$2}'`; [ -n "${PORT}" ] && echo "${PORT} ${DOMAIN}"; done < <(virsh list | sed -n '/^-\+$/,/^$/p' | sed -e '/^ *-\+ *$/d' | awk '{print $2}' | sed -e '/^[ \t]*$/d')
END
)
}

# file descriptions IPADDRES<spaces>group1<spaces>group2<spaces>groupN
# файл описывающий все хосты и группы в которые они входят
CONFIG=$(cat <<EOF
10.55.24.156     v03-a v_cluster all
10.55.24.157     v03-b v_cluster all
10.55.24.158     v03-c v_cluster all
10.55.24.159     v03-t           all sergey
10.55.24.253     h01             all
10.55.24.249     s01-0 s_cluster all
10.55.24.251     s01-1 s_cluster all
EOF
)

  HOSTGROUPS=`echo "${CONFIG}" | awk '{for (i=2;i<=NF;i++) {printf("%s\n", $i);}}' | sort -u`

  while [ true ] ; do
    PS3="Type a group number or 'q' to quit: "
    select HOSTGROUP in ${HOSTGROUPS} ; do
      if [ -n "${HOSTGROUP}" ] ; then
        break
      else
        if [[ ${REPLY} =~ [Qq] ]] ; then
          echo -e "Quit."
          exit 0
        fi
      fi
    done

    LOOPLEVEL="1"

    while [ "${LOOPLEVEL}" -eq "1" ] ; do

      FULLLIST=""
      # получить список хостов
      while read HOST1 GROUPNAME ; do
        echo -e "${GROUPNAME}"
        FMT="ssh -L localhost:%d:localhost:%d -N root@%s& pid=\$!;sleep 2;vncviewer localhost:%d;kill \$pid;sleep 1;echo \" \" # %s(%s)\n"
        ITEM=`GETVNCPORTS "${HOST1}"  | awk -v fmt="${FMT}" -v hst="${GROUPNAME}" '{printf(fmt, $2, $2, $1, $2, $3, hst)}'`
        FULLLIST=`echo -e "${FULLLIST}\n${ITEM}"`
      done < <(echo -e "${CONFIG}" | awk -v group="${HOSTGROUP}" '{if ($0 ~ group) {print $1" "$2}}')
      # убрать пустые строки
      FULLLIST=`echo -e "${FULLLIST}" | sed -e '/^$/d'`

      VMLIST=`echo -e "${FULLLIST}" | sed -e 's/^[^#]*# \([^ ]*\)$/\1/g' | sort`

      if [ -z "${VMLIST}" ] ; then
        echo -e "No VM is running on host group \"${HOSTGROUP}\""
        LOOPLEVEL="0"
        break
      fi

      PS3="Type a number or 'q' to return to previous menu, 'r' to reread list: "
      select VMNAME in ${VMLIST} ; do
        if [ -n "${VMNAME}" ] ; then
          break
        else
          if [[ ${REPLY} =~ [Qq] ]] ; then
            echo -e "Quit."
            LOOPLEVEL="0"
            break
          elif [[ ${REPLY} =~ [Rr] ]] ; then
            # next loop with reread
            break
          fi
        fi
      done
      if [ -n "${VMNAME}" ] ; then
        COMMANDSTR=`echo -e "${FULLLIST}" | sed -n 's/^\([^#]*\)# '${VMNAME}'$/\1/p'`
        echo -e "${COMMANDSTR}"
        eval "${COMMANDSTR}"
        echo -e "All done."
      fi
    done
  done
Рекоментация!Для соединения ssh будет требоваться аутентификация на удалённом сервере. Сделать это удобнее используя сертификаты. Чтобы каждый раз не открывать сертификат паролем стоит добавить их один раз в ssh-agent при помощи ssh-add /home/user001/.ssh/id_rsa

Скрипт копирования нескольких LV

Однострочный скрипт копирования логических томов LV. Например для копирования дисков виртуальных машин.

Тестовый вариант отображает команду на экран:

# for VOL in "lv_vm3_disk0" "lv_server_fm-disk0" "lv_vm1_disk0" ; do echo -e "dd if=/dev/vg_vm/${VOL} of=/mnt/tmp1/${VOL} bs=2M iflag=direct oflag=direct" ; done
dd if=/dev/vg_vm/lv_vm3_disk0 of=/mnt/tmp1/lv_vm3_disk0 bs=2M iflag=direct oflag=direct
dd if=/dev/vg_vm/lv_server_fm-disk0 of=/mnt/tmp1/lv_server_fm-disk0 bs=2M iflag=direct oflag=direct
dd if=/dev/vg_vm/lv_vm1_disk0 of=/mnt/tmp1/lv_vm1_disk0 bs=2M iflag=direct oflag=direct

А это рабочий вариант:

# for VOL in "lv_vm3_disk0" "lv_server_fm-disk0" "lv_vm1_disk0" ; do dd if=/dev/vg_vm/${VOL} of=/mnt/tmp1/${VOL} bs=2M iflag=direct oflag=direct ; done
81920+0 records in
81920+0 records out
171798691840 bytes (172 GB) copied, 2433.05 s, 70.6 MB/s
75002+0 records in
75002+0 records out
157290594304 bytes (157 GB) copied, 2525.82 s, 62.3 MB/s
128000+0 records in
128000+0 records out
268435456000 bytes (268 GB) copied, 3628.6 s, 74.0 MB/s
Рекоментация!Так как копирование логических томов это длительная операция то такие команды лучше запускать в screen.

Как изменить разделитель полей команды ps

Команда ps имеет множество ключей один из которых позволяет определить свой разделитель полей, если требуется распарсить поля содержащие пробелы (например аргументы командной строки процессов)

ps -eo "%p\t%a"

Для того чтобы вставить табуляцию в качестве разделителя нужно либо воспользоваться sed для замены \t на табуляцию или воспользоваться echo -e но удобнее немного изменить строку исползуя хак:

ps -eo "%p"$'\011'"%a"

В использовании команды есть одна непонятная особенность: чтобы аргумент %a вывел полные параметры, а не обрезал их по ширине, он должен быть использован в самом конце форматной строки. Если после него встретится хотя бы один символ включая пробел то ширина поля args будет ограничена. Поле будет обрезано. Мне не удалось заставить вывести полный аргумент никакими перенаправлениями в pipe или переменными COLUMNS как это описано в документации.

ОБЫЧНЫЕ AIX коды описаны ниже.

       CODE   NORMAL   HEADER
       %C     pcpu     %CPU
       %G     group    GROUP
       %P     ppid     PPID
       %U     user     USER
       %a     args     COMMAND
       %c     comm     COMMAND
       %g     rgroup   RGROUP
       %n     nice     NI
       %p     pid      PID
       %r     pgid     PGID
       %t     etime    ELAPSED
       %u     ruser    RUSER
       %x     time     TIME
       %y     tty      TTY
       %z     vsz      VSZ

Как из каталога web сервера загрузить все файлы

Если отбросить все декорации в виде index.html* файлов и ограничить скорость стягивания на уровне 1 мегабайта в секунду, использовать аутентификацию то это может выглядеть так:

wget -r --no-parent --no-directories --reject "index.html*" --limit-rate=1m --user=vasily --password=terkin http://youngblogger.hoster-ok.com/usersdata/vaslily/

Получение списка соответствия портов рейд контроллера дискам в системе

Имеем RAID контроллер который экспортирует свои диски в систему как набор дисков (JBOD).
Нужно получить какой физический порт какому устройству в системе соответствует.

Пример был сделан для контроллера 3ware и CentOS release 6.5 (Final). Но с небольшими поправками подойдёт и для других контроллеров.

Unit  UnitType  Status         %RCmpl  %V/I/M  Stripe  Size(GB)  Cache  AVrfy
------------------------------------------------------------------------------
u0    JBOD      OK             -       -       -       931.513   Ri     OFF
u1    JBOD      OK             -       -       -       1863.02   Ri     OFF
u2    JBOD      OK             -       -       -       1863.02   Ri     OFF
u3    JBOD      OK             -       -       -       1863.02   Ri     OFF

VPort Status         Unit Size      Type  Phy Encl-Slot    Model
------------------------------------------------------------------------------
p0    OK             u0   931.51 GB SATA  0   -            WL1000GSA64RA100B
p1    OK             u1   1.82 TB   SATA  1   -            WDC WD2002FYPS-02W3
p2    OK             u2   1.82 TB   SATA  2   -            WDC WD2002FYPS-02W3
p3    OK             u3   1.82 TB   SATA  3   -            WDC WD2002FYPS-02W3

Continue reading Получение списка соответствия портов рейд контроллера дискам в системе

Как избавиться от диакритики

Один из моих bash скриптов обрабатывающих входящие счета от чешской компании вдруг сломался. Оказалось, что тот кто фомирует счета допустил ошибку в шаблоне и одна из букв перестала быть с диакритикой. Чтобы впредь из-за такой мелочи не ломался скрипт я решил избавить входящий документ от диакритики полностью. Можно было использовать recode но зачем если sed справляется с транслитерацией не менее быстро, а главное что он имеется в любой *nix системе.

echo "Daňový portál" | sed 'y/áéíóúýčďěňřšťžůÁÉÍÓÚÝČĎĚŇŘŠŤŽŮ/aeiouycdenrstzuAEIOUYCDENRSTZU/'
Danovy portal

Как узнать путь откуда запущен bash скрипт

BASEDIR=$(readlink -e "$0")
if [ $? -ne 0 ] ; then
  echo -e "Script path get error."
  exit 1
fi
BASEDIR="${BASEDIR%/*}"
echo "${BASEDIR}" 
exit 0

В дополнение к команде readlink есть ещё realpath и realname которые вернут полный путь и имя переданного им файла. Разумеется файл должен существовать.

Но внимание! Приведённые выше команды вернут путь на сам файл даже если скрипт запустили через симлинк (symlink). Например может понадобиться чтобы скрипт мог что либо записать в папку из которой был запущен даже через симлинк. Чтобы этого добиться необходимо поступить например вот так:

SAVEDIR=`pwd`
BASEDIR=`cd "$(dirname "$0")" && pwd`
cd "${SAVEDIR}"
echo -e "${BASEDIR}"
exit 0

Оператор цикла for в bash

Великая магия оператора for о которую приходится биться каждый раз пока не усвоишь урок, кроется в том что он рубит входные данные по символам разделителям которые перечислены в переменной IFS=

Не менее странным является и то, что этой переменной невозможно присвоить один байт-символ CR (возврат каретки) 0xA.
Никакие танцы с бубнами и операторы echo не дают этой возможности.
Два символа можно

IFS=$(echo -en "\n\b") # работает
echo -en "$IFS" | hexdump -C
00000000  0a 08                                             |..|
00000002

но один или много \n — не получается.

IFS=$(echo -en "\n\n\n\n\n") # не работает. Переменная будет пустой.
echo -en "$IFS" | hexdump -C # да говорю же следующая строка будет пустой

IFS=$(echo -en "A" | tr 'A' '\n') # не пойдёт!
IFS="\
\
" # тоже не будет работать

Continue reading Оператор цикла for в bash

ssh внутри while цикла который получает данные из stdin

Наткнулся я на то что скрипт запущенный локально — работает, а если его запустить на удалённой машине он вываливается из цикла while

#!/bin/bash

  SERVERS="10.10.1.6\n10.15.4.240"

  echo -e "${SERVERS}" | while read SERVER ; do
    echo -e "${SERVER}"
    ssh root@${SERVER} "uptime"
  done

Как оказалось проблема в том что ssh съедает stdin в первой итерации цикла.
Для меня это было неожиданно, однако лечится либо опцией -n либо перенаправлением stdin на < /dev/null .

#!/bin/bash

  SERVERS="10.10.1.6\n10.15.4.240"

  echo -e "${SERVERS}" | while read SERVER ; do
    echo -e "${SERVER}"
    ssh -n root@${SERVER} "uptime"
    ssh root@${SERVER} "uptime" < /dev/null
  done