LINUX.ORG.RU

bash, sqlite3, insert.


0

0

Пишу скрипт, который сохраняет конфигурационные файлы в бд sqlite3. Именно как текст, чтобы потом можно было бы их грепать. Проблема в том, что могу сохранить содержимое не для всех файлов, а только некоторых.
Для краткости привожу не весь текст, а то, что вызывает вопрос. На самом деле база данных немного сложнее.

$sqlite3 test.db "create table tbl ( N INTEGER, NAME TEXT, CONF TEXT );"

$sqlite3 test.db "insert into tbl ( N, NAME, CONF ) values (1, '/etc/fstab', '`cat /etc/fstab`' ); "

нет ошибок, select показывает то, что нужно. Но

$sqlite3 test.db "insert into tbl ( N, NAME, CONF ) values (1, '/etc/bash.bashrc', '`cat /etc/bash.bashrc`' ); "

Ошибка.
SQL error: unrecognized token: "#"

в google упоминается об этом, но что делать не понимаю.
Помогите разобраться. Как сохранить текст файла в предназначенном для этого поле. Причем, знаки "#" есть как в /etc/fstab, так и в /etc/bash.bashrc .




anonymous

Ответ на: комментарий от CtrlAltBs

cat /etc/bash.bashrc
# System-wide .bashrc file for interactive bash(1) shells.

# To enable the settings / commands in this file for login shells as well,
# this file has to be sourced in /etc/profile.

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize

# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
    debian_chroot=$(cat /etc/debian_chroot)
fi

# set a fancy prompt (non-color, overwrite the one in /etc/profile)
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '

# Commented out, don't overwrite xterm -T "title" -n "icontitle" by default.
# If this is an xterm set the title to user@host:dir
#case "$TERM" in
#xterm*|rxvt*)
#    PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
#    ;;
#*)
#    ;;
#esac

# enable bash completion in interactive shells
#if [ -f /etc/bash_completion ]; then
#    . /etc/bash_completion
#fi

anonymous
()
Ответ на: комментарий от CtrlAltBs

/etc/bash.bashrc - дефолтный. В нем просто текст, естесственно не экранированный.

anonymous
()

попробуй
shopt -o interactive_comments
$sqlite3 test.db "insert into tbl ( N, NAME, CONF ) values (1, '/etc/bash.bashrc', '`cat /etc/bash.bashrc`' ); "
shopt -u interactive_comments

может, баш пытается парсить # (хотя в '' по идее, не должен)

anonymous
()
Ответ на: комментарий от anonymous

Спасибо за ответ, но все то же...

>shopt -o interactive_comments

$bash: shopt: interactive_comments: invalid option name

$shopt -s interactive_comments

$shopt | grep interactive_comments

interactive_comments on

$sqlite3 test.db "insert into tbl ( N, NAME, CONF ) values (1, '/etc/bash.bashrc', '`cat /etc/bash.bashrc`' ); "

SQL error: unrecognized token: "#"

$shopt -u interactive_comments

anonymous
()

Вариант

$STR=`cat /etc/bash.bashrc` && sqlite3 test.db "insert into tbl ( N, NAME, CONF ) values (1, '/etc/bash.bashrc', '${STR}' ); "

Выдаёт ту же ошибку

anonymous
()
Ответ на: комментарий от anonymous

перепутал: наоборот, попробуй сбросить опцию.
shopt -u interactive_comments
..
shopt -s interactive_comments
Идея в том чтобы заэкранировать '#'

interactive_comments
Если эта опция установлена, слово, начинающееся символом #, и все остальные символы в этой строке игнорируются интерактивным команжным интерпретатором (см. раздел "КОММЕНТАРИИ" ранее). Эта опция включена по умолчанию.

anonymous
()
Ответ на: комментарий от anonymous

>перепутал: наоборот, попробуй сбросить опцию.

>shopt -u interactive_comments

всё то же:

SQL error: unrecognized token: "#"

anonymous
()
Ответ на: комментарий от anonymous

$echo sqlite3 test.db "insert into tbl ( N, NAME, CONF ) values (1, '/etc/bash.bashrc', '`cat /etc/bash.bashrc`' ); "

echo sqlite3 test.db "insert into tbl ( N, NAME, CONF ) values (1, '/etc/bash.bashrc', '`cat /etc/bash.bashrc`' ); "
sqlite3 test.db insert into tbl ( N, NAME, CONF ) values (1, '/etc/bash.bashrc', '# System-wide .bashrc file for interactive bash(1) shells.

# To enable the settings / commands in this file for login shells as well,
# this file has to be sourced in /etc/profile.

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize

# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
    debian_chroot=$(cat /etc/debian_chroot)
fi

# set a fancy prompt (non-color, overwrite the one in /etc/profile)
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '

# Commented out, don't overwrite xterm -T "title" -n "icontitle" by default.
# If this is an xterm set the title to user@host:dir
#case "$TERM" in
#xterm*|rxvt*)
#    PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
#    ;;
#*)
#    ;;
#esac

# enable bash completion in interactive shells
#if [ -f /etc/bash_completion ]; then
#    . /etc/bash_completion
#fi' );


anonymous
()
Ответ на: комментарий от anonymous

>2. bash --debug script.sh

$cat test.sh
#!/bin/bash
sqlite3 test.db "create table tbl ( N INTEGER, NAME TEXT, CONF TEXT );"

sqlite3 test.db "insert into tbl ( N, NAME, CONF ) values (1, '/etc/bash.bashrc', '`cat /etc/bash.bashrc`' );"

exit 0

$bash --debug test.sh

SQL error: unrecognized token: "#"

anonymous
()
Ответ на: комментарий от anonymous

что-то вроде
$STR=`cat /etc/bash.bashrc` && sqlite3 test.db "insert into tbl ( N, NAME, CONF ) values (1, \'/etc/bash.bashrc\', \'${'STR}\' ); "

$'STRING

и потом, доставая из базы учитывать что строка в отквоченном виде. Что-то вроде PHP-шного htmlspecialchars

anonymous
()
Ответ на: комментарий от anonymous

$cat test.sh

#!/bin/bash

STR=`cat /etc/bash.bashrc`
STR=\'${STR}\'
echo "${STR}"
read a
sqlite3 test.db "create table tbl ( N INTEGER, NAME TEXT, CONF TEXT );"
sqlite3 test.db "insert into tbl ( N, NAME, CONF ) values (1, '/etc/bash.bashrc', '${STR}' );"

exit 0

$./test.sh
'# System-wide .bashrc file for interactive bash(1) shells.

# To enable the settings / commands in this file for login shells as well,
# this file has to be sourced in /etc/profile.

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize

# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
    debian_chroot=$(cat /etc/debian_chroot)
fi

# set a fancy prompt (non-color, overwrite the one in /etc/profile)
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '

# Commented out, don't overwrite xterm -T "title" -n "icontitle" by default.
# If this is an xterm set the title to user@host:dir
#case "$TERM" in
#xterm*|rxvt*)
#    PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
#    ;;
#*)
#    ;;
#esac

# enable bash completion in interactive shells
#if [ -f /etc/bash_completion ]; then
#    . /etc/bash_completion
#fi'

SQL error: unrecognized token: "#"

anonymous
()
Ответ на: комментарий от anonymous

как вариант, запускать не через
$sqlite "insert into (..) values (..)"
а через

dummy_stub=$($sqlite << EOF_MARK_THAT_IS_LONG_AND_ODD_ENOUGH_DO_NOT_MEET_IN_THE_BASH_BASHRC
INSERT into tbl ( N, NAME, CONF )
values (1, '/etc/bash.bashrc',
$(cat /etc/bash.bashrc)
EOF_MARK_THAT_IS_LONG_AND_ODD_ENOUGH_DO_NOT_MEET_IN_THE_BASH_BASHRC
)

anonymous
()
Ответ на: комментарий от anonymous

по-моему, минимальный вариант, воспроизводящий ошибку:
$sqlite "insert into ... values( ... ,'$c');

$sqlite "insert into ... values( ... ,'qwertty
#asd
other');

то есть, переносы строк. Их надо как-то отквотить, то есть, или через sed заменить \n на \\n (чтобы \ был последним в строке и квотил её, или использовать cat -v .. и ложить в таком виде в базу и расквочивать обратно, доставая из базы)

обязательно проверить на инъекции, что будет если в многострочной переменной $c попадётся ' " \ -- % ; и т.п.

гы, есть вот такой вариант (подразумевая, что /etc уже лежит например в git): не хранить файлы-блобы в базе. Вообще. Просто пользуясь командами вроде git-ls-tree, git-cat-file получать хеши этих файлов-блобов.

И хранить в базе уже эти хеши (от содержимого файлов). И не морочить себе голову возможными инъекциями в конфигах.

anonymous
()

ещё можно попробовать сменить язык. Чтобы bash-like shell не пытался парсить # и переводы строк, а сформированная sqlite строка была подготовлена через prepare а не тупым интерпретатором (который сам пытается съесть переносы строк в подставляемой строке)

anonymous
()
Ответ на: комментарий от anonymous

>по-моему, минимальный вариант, воспроизводящий ошибку:
$sqlite "insert into ... values( ... ,'$c');

>$sqlite "insert into ... values( ... ,'qwertty
#asd
other'); 

$ cat test.sh
#!/bin/bash
STR='qwertty
#asd
other'
echo "${STR}"
read a
sqlite3 test.db "create table tbl ( N INTEGER, NAME TEXT, CONF TEXT );"
sqlite3 test.db "insert into tbl ( N, NAME, CONF ) values (1, '/etc/bash.bashrc', '${STR}' );"

exit 0

$ ./test.sh
qwertty
#asd
other

Ошибок нет....

$ sqlite3 test.db
SQLite version 3.3.8
Enter ".help" for instructions
sqlite> select * from tbl;
1|/etc/bash.bashrc|qwertty
#asd
other
sqlite> .q




anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.