вторник, 26 апреля 2011 г.

[bash] Построчное чтение файла и ssh

Пишем мы скрипт на баше, и нужно нам считать файл построчно, это делается вот так
cat number.txt | while read line 
do
   echo $line
done
Но вот нам потребовалось сделать в теле цикла что то по ssh. Мы смело вставляем нужный код
cat number.txt | while read line 
do
   echo $line
   ssh user@127.0.0.1 "ls"
done
(представим что у нас настроена авторизация по открытому ключу).
И... и этот код будет работать не так как нам хотелось бы. Отработает только одна итерация цикла, не зависимо от того сколько строк в файле.

Проблема заключается в том что cat делает вывод в stdin из которого конвейером данные переходят в read. Но и ssh тоже использует stdin для своих целей и сливает все данные в себя (либо просто "забывает" их). И по когда управление будет снова передано на проверку условия, в stdin уже будет пусто и мы выйдем из цикла. Неожиданно ? да :)

Так как же нам решить эту проблему ? А вот так
exec 10<$PAIR_CONFIG
while read line <&10
do
   echo $line
   ssh user@127.0.0.1 "ls"
done
Мы связываем файловый дескриптор №10 с нужным нам файлом. И далее производим чтение уже из этого потока.

среда, 6 апреля 2011 г.

[C++] Текущая директория (кроссплатформенно)

Ниже приведены три способа получить полный путь до директории из которой был запущен исполняемый файл


#ifdef _LINUX
#include <limits.h>
#include <string.h>

char path[PATH_MAX + 1] = { 0 };
ssize_t len = readlink("/proc/self/exe", path, PATH_MAX);
path[len] = 0;
char* p = strrchr(path, '/');
if(p) *(p + 1) = 0;
else path[0] = 0;
#else
#include <windows.h>

char path[_MAX_PATH];
GetModuleFileName(NULL, path, _MAX_PATH);
#endif
#include <boost/filesystem/operations.hpp>

std::string path = boost::filesystem::current_path().string();

вторник, 5 апреля 2011 г.

[Часть 2] Cmake: автоматизированная сборка и установка

Теперь рассмотрим процесс подготовки Cmake для make install.

Итак, имеем конкретный CMakeLists для сборки определенного проекта. Далее все просто и быстро
if (UNIX)
linux_install(${PROJECT_NAME})

# возможно проекту требуются какие то внешние либы
install(FILES $ENV{SOME_ROOT}/lib/release/libsome.so.1.0
DESTINATION ${PROJECT_NAME}/lib RENAME libsome.so.1)
endif()

Далее где то должна быть определена используемая функция
function(linux_install PROJECT_NAME)
set_target_properties(${PROJECT_NAME} PROPERTIES RESOURCE ${PROJECT_NAME}_ETC_FILES)

install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION ${PROJECT_NAME}/bin
RESOURCE DESTINATION ${PROJECT_NAME}/etc
)
install(PROGRAMS ${${PROJECT_NAME}_BIN_FILES} DESTINATION ${PROJECT_NAME}/bin)
install(FILES ${${PROJECT_NAME}_LIB_FILES} DESTINATION ${PROJECT_NAME}/lib})
endfunction(linux_install)

Здесь мы как раз и использовали ранее полученные переменные имя_проекта_BIN_FILES, имя_проекта_ETC_FILES, имя_проекта_LIB_FILES

Например если у нас имеется в наличии несколько разных тестов, для разные подпроектов, то неплохо бы их собрать вместе для тестера

function(linux_install_test PROJECT_NAME PROJECT_DIR)
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${PROJECT_DIR}/bin)

install(PROGRAMS ${${PROJECT_DIR}_BIN_FILES} DESTINATION ${PROJECT_DIR}/bin)
install(FILES ${${PROJECT_DIR}_ETC_FILES} DESTINATION ${PROJECT_DIR}/etc})
install(FILES ${${PROJECT_DIR}_LIB_FILES} DESTINATION ${PROJECT_DIR}/lib})
endfunction(linux_install_test)

Где PROJECT_DIR директория ресурсов для теста и она же название директории установки тестов.

И так же иметь возможность устанавливать библиотеки которые разрабатываются как часть проекта
function(linux_install_lib PROGECT_NAME)
FOREACH(INSTALL_DIR ${LIST_DIR_PROJECT})
install(TARGETS ${PROJECT_NAME}
LIBRARY DESTINATION ${INSTALL_DIR}/lib
RESOURCE DESTINATION ${INSTALL_DIR}/lib)
ENDFOREACH(INSTALL_DIR)
endfunction(linux_install_lib)