LINUX.ORG.RU

Обработка всех файлов из каталога

 ,


0

2

У меня вопросы по программированию на shell. Вот например такой скрипт (запуск в Debian):

#!/bin/sh
for DEB in /home/user/packages/*.deb
do
   dpkg --install $DEB
done
установит все deb-пакеты, находящиеся в каталоге /home/user/packages? А что будет, если каталог будет пустой, выведется ошибка? Как улучшить скрипт, чтобы ошибка не выводилась?
Для shell-скриптов текущим каталогом является тот, в котором скрипт расположен? То есть если я размещу скрипт в /home/user/packages то строку условия смогу упростить до:
for DEB in *.deb

★★★★★

Последнее исправление: sunny1983 (всего исправлений: 1)

Для shell-скриптов текущим каталогом является тот, в котором скрипт расположен?

Нет, для shell-скриптов текущим каталогом является текущий каталог

То есть если я размещу скрипт в /home/user/packages то строку условия смогу упрастить до:

нет

упрастить

http://gramota.ru/slovari/dic/?word=%F3%EF%F0%E0%F1%F2%E8%F2%FC&all=x

derlafff ★★★★★
()
  • Ошибки не будет;
  • Для проверки добавляй перед командой echo. Тогда сможешь безопасно поиграть со скриптом;
  • Для ещё более лютой проверки (считай отладки) запускай скрипт командой bash -x <скрипт>. В этом случае echo добавлять не нужно, т.к. он и так выведет тебе всё, НО тогда команды будут реально выполнены;
  • Всегда проверяй свои скрипты.

упрастить до

  • Можно, но опасно. Лучше передавай путь аргументом;
  • Скачай и прочитай книжку Розенталя;
ziemin ★★
()

find /home/user/packages -maxdepth 1 -type f -name '*.deb' | xargs --no-run-if-empty dpkg --install

# -maxdepth 1 если не надо в поддиректории лезть

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

Нет смысла ставить deb'ы по одному

Тогда так:

find /home/user/packages/ -maxdepth 1 -type f -name '*.deb' -exec dpkg --install {} +

ТС дурак и ты за ним идешь?

Ну уж извините, в говнодебианах не разбираюсь и не собираюсь

derlafff ★★★★★
()
Последнее исправление: derlafff (всего исправлений: 1)
Ответ на: комментарий от sdio

в говне, в котором разбираешься.

теги: bash

ну я в нем и копаюсь, лол

Так шел бы

«моё решение хуже, нужно сорваться на бедную поняшку»

derlafff ★★★★★
()
Ответ на: комментарий от ziemin

Скачай и прочитай книжку Розенталя;

Думал руководство по shell-скриптам, а оказалось учебник по правописанию ))))

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

Соснёт с whitespace в имени файла же.

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

ОМГ.

#!/bin/bash
shopt -s failglob
dpkg -i /home/user/packages/*.deb

Zmicier ★★★★★
()
Ответ на: комментарий от sdio

ТС дурак и ты за ним идешь?

Мне вообще не нужно ставить deb'ы через dpkg. Это просто пример для задачи обработки всех файлов скриптом.

Нет, для shell-скриптов текущим каталогом является текущий каталог

То есть мне нужно, чтобы в скрипте была смена текущего каталога также как и в интерактивном режиме командой cd?

Кстати вариант через find мне не подходит, только через for, потому что по задумке между do и done потом ещё будут команды вставляться.

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

Молодцы ребятки, концепт вы поняли, детали в man'e.

sdio ★★★★★
()
Ответ на: комментарий от sunny1983

Если тебе нужна просто маска, то, как уже привели пример,

shopt -s failglob
for file in <mask>; do
    <actions>
done

Если нет, то вот так (read -d работает только в bash):

find <args> -print0 | while read -rd '' file; do
    <actions>
done

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

ТС дурак ...

Мне вообще не нужно ставить deb'ы через dpkg

Все-таки упоминания умственных способностей в формулировании вопроса оказались не беспочвенными.

sdio ★★★★★
()
Ответ на: комментарий от sunny1983
#!/bin/sh
dir="$1"

if [ -d "$dir" ] && ls "$dir"/*.deb > /dev/null
then 
  for DEB in "$dir"/*.deb
  do
    echo "installing $DEB..."
    dpkg --install "$DEB"
  done
else
  echo "ERROR: empty or incorrect path or no packages"
  echo "usage: $0 /path"
fi
ziemin ★★
()
Ответ на: комментарий от sin_a

Есть и такое:

http://www.opennet.ru/docs/RUS/bash_scripting_guide/

Не поверишь, но именно этот ман я сейчас уже третий день читаю. Просто для проверки, правильно ли я всё усвоил, я могу спрашивать «старших товарищей».

Тогда улучшеный скрипт такой получается должен быть?

#!/bin/sh
shopt -s failglob
cd $PWD
for DEB in $(ls -1 *.deb > /dev/null)
do
   dpkg --install $DEB
   echo "$DEB installed"
done
Извините за глупые вопросы, учусь. Проверить работу не могу, я сейчас не под линуксом.

sunny1983 ★★★★★
() автор топика
Ответ на: комментарий от sunny1983

Нет, этот вариант подавится на пробелах в именах файлов. Замените $(...) на *. Об ошибке позаботится failglob. Переходить в текущий каталог не нужно, скрипт уже в нём уже находится (когда Вы из /a/b/c/ запускаете /usr/bin/whatever, PWD для него становится /a/b/c/, а не /usr/bin/).

AITap ★★★★★
()
Ответ на: комментарий от sunny1983

Проверить работу не могу, я сейчас не под линуксом.

bash есть и под венду.

ziemin ★★
()
Ответ на: комментарий от sunny1983

Facepalm.tar.bz2

cd $PWD

Во-первых, всегда экранируй переменные кавычками, если не хочешь передать произвольное число аргументов (иначе whitespace будет восприниматься как разделитель аргументов): cd "$PWD".

Во-вторых, эта конструкция бессмысленна, т.к. PWD — и есть текущий каталог.

$(ls -1 *.deb > /dev/null)

Зачем ты перенаправляешь вывод в /dev/null? Зачем -1? Зачем ls?

shopt -s failglob
for DEB in *.deb; do
    ...
done
^ же!

dpkg --install $DEB

Опять же, dpkg --install "$DEB".

echo "$DEB installed"

А если не установился? 4.2 же!

dpkg --install "$DEB" \
     && echo "$DEB installed" \
     || echo "$DEB NOT installed"

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

кривое

будто бы у тебя менее кривое, уважаемый тов. дебианомастер

derlafff ★★★★★
()
Последнее исправление: derlafff (всего исправлений: 2)
Ответ на: комментарий от AITap

Понял, что PWD бессмысленно. А как сменить текущий каталог на каталог местоположения скрипта? Вот ziemin предлагает dir=«$1», но я что-то не пойму, ведь написано, что $1 это первый параметр.

sunny1983 ★★★★★
() автор топика
Ответ на: комментарий от sunny1983
cd "$(dirname "$(readlink -e "$0")")"

$0 - наш файл, либо по относительному пути (если его вызвали по нему), либо по абсолютному (если вызвали по имени, и он был найден в $PATH). В обоих случаях readlink возвратит абсолютный путь к файлу (осторожнее с симлинками! см. также realpath в новых версиях coreutils). dirname вернёт «диреторию» из этого пути, а cd в неё перейдёт.

AITap ★★★★★
()
Ответ на: комментарий от sunny1983

Варианты.

  1. Вызывать скрипт с параметром (как я предлагаю): dir="$1";
  2. Использовать текущий каталог (откуда вызван скрипт): dir="$PWD";
  3. Использовать каталог скрипта (дурацкая затея): dir=`realpath "$0"`; dir=`dirname "$dir"`
  4. Использовать постоянный путь (как выше):dir="/home/user/packages";
ziemin ★★
()
Ответ на: комментарий от sunny1983

Если ты не собираешься его source'ать, то

cd -- "$(dirname -- "$(which -- "${0}" 2>&- || printf '%s\n' "${0}")")"

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

Всё, вопросы со сменой каталога пропали, оказалось, что это вообще не нужно, так так нужно чтобы текущим каталогом на момент выполнение цикла был / потому что tar.

Зная какие дистрибы предпочитают пони, ладно уж признаюсь, что идея у меня вообще не для Debian, а для Slackware, просто идея сильно упоротая чтобы в ней просто так признаваться - нужно установить пакеты в автоматическом режиме при загрузке с initrd, а там нет ни slackpkg, ни installpkg, устанавливать только через tar, но посколько Slackware я знаю плохо, а Debian хорошо - то вопрос задал на примере второго. Всё, больше поводов кидаться в меня тапками не осталось?

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

#!/bin/sh
shopt -s failglob
USERDIR=$PWD
cd /
for TXZ in "$DIR"/*.txz
do
   cat "$TXZ" | xz -d | tar -x
   chmod 777 /install/doinst.sh
   /install/doinst.sh
   rm -fR /install
done
cd "$USERDIR"

sunny1983 ★★★★★
() автор топика
Последнее исправление: sunny1983 (всего исправлений: 1)
Ответ на: комментарий от ziemin

Не можно, а нужно, потому что в слаковских doinst.sh нет sha-bang (#!/bin/sh).

Да, и кто будет чистить то говно, что он наставил мимо installpkg? Может ему лучше installpkg с собой таскать и просто вызывать installpkg "${DIR}"/*.txz?

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

А потому что в этой урезаной системе, грузимой с initrd нет манов, а справка выводимая по «tar --help» ничего не говорит о том, умеет ли данная версия tar работать с сжатием xz.

sunny1983 ★★★★★
() автор топика
Ответ на: комментарий от sunny1983

Если там действительно нет installpkg, то я бы выводил список распакованных файлов в отдельный файл (tar xJvf "$TXZ" > /tmp/file), а потом по этому списочку аккуратненько удалял.

Надеюсь инсталляция означает копирование, а не то, что файлы распаковываются прям поверх корня, а скрипт просто конфиги правит?

ziemin ★★
()
Последнее исправление: ziemin (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.