bash->установка бита владельца директории из списка

Недавно пришлось решать немного странную задачку на BASH. Был список в текстовом формате:

группа=путь

Нужно было пройтись по каждому элементу списка и установить группу указанного в нём же.
На сервере стоял старый BASH, ассоциативных массивов, в котором ещё небыло.

Написал вот это:

#!/bin/bash
 
if [ "$1" == "--help" ] || [ "$1" == "help" ]
then
	echo "Использование: <имя скрипта> <путь до списка> <путь до лог-файла> Все параметры не обязательны. Если скрипт не получит путь до файла-списка - попытается открыть файл 'list' в своей директории. Тоже самое касается лог-файла.";
	exit 0;
fi
 
if [ -z "$2" ]
then
	log="log.txt";
else
	log=$2;
fi
 
mess () {
 
	date=`date +%D-%r`;
	echo "[ $date] $1" >> $log;
	echo "[ $date] $1";
 
	if [ "$2" -eq 1 ]
	then
		exit 1;
	fi
}
 
if [ -w "$log" ]
then
echo "";
else
	mess "Лог-файл не доступен для записи." 0;
fi
 
if [ -z "$1" ]
then
	l="list";
else
	l=$1;
fi
 
list=$(cat $l);
 
if [ -z "$list" ]
then
	mess "Ошибка при открытии файла-списка!" 1;
fi
 
for i in $list;
do
	group=`echo $i|cut -d "=" -f 1`
	dir=`echo $i|cut -d "=" -f 2`
 
	if `chgrp -R $group $dir`
	then
		mess "Установлена группа '$group' для дир. '$dir'" 0;
	else
		mess "Ошибка при обработке дир. '$dir'" 0;
	fi
done

Скрипт по умолчанию считывает текстовый файл «list», лежащий рядом, в его директории. Если есть потребность указать файл из другой директории, вызывайте скрипт так:

script <путь-до-файл-листа> <путь-до-лог-файла>

Ещё можно посмотреть help-сообщение, командой script –help.

  • Трэкбеки закрыты
  • Комментарии (4)
    • Konstantin Khomoutov
    • 25 июля, 2010

    Разбиение строк на поля можно было сделать чуть элегантнее — при помощи временной смены IFS. Пример:
    $ while IFS=’=’ read A B; do echo «A: $A; B: $B»; done
    foo=bar
    A: foo; B: bar
    quux=xyzzy
    A: quux; B: xyzzy
    ^D

    Также круглые скобки после if непонятны — они организуют сабшелл. По-моему, достаточно было простого:
    if chgrp -R $group $dir; then …

  1. >Также круглые скобки после if непонятны

    Обычное правило хорошего тона – разделение процессов между собой )
    Так обычно делают, когда пишут, например на C. Тяжёлые процессы чаще всего отдаются процессу-потомку, чтобы операционная система смогла выдержать необходимый баланс ресурсов.

    $ while IFS=’=’ read A B; do echo «A: $A; B: $B»; done
    foo=bar
    A: foo; B: bar
    quux=xyzzy
    A: quux; B: xyzzy
    ^D

    Спасибо за трюк, раньше так никогда не делал. Вообще задумка была реализовать explode() из PHP…

    • Konstantin Khomoutov
    • 25 июля, 2010

    Sb0y :
    >Также круглые скобки после if непонятны
    Обычное правило хорошего тона – разделение процессов между собой )
    Так обычно делают, когда пишут, например на C. Тяжёлые процессы чаще всего отдаются процессу-потомку, чтобы операционная система смогла выдержать необходимый баланс ресурсов.

    Вы что-то путаете. С этим кодом есть две проблемы (вторую я при первом просмотре не увидел).

    Первая: выгрузка вычислений или других операций в другой процесс нужна только для того, чтобы освободить исходный процесс для *параллельного* решения другой задачи. У Вас же создаётся сабшелл, он исполняет скрипт «chgrp -R $group $dir» (точнее, вместо указанных переменных в скрипт будут подставлены их значения перед передачей), а исходный процесс в это время тупо спит в вызове waitpid() чтобы дождаться завершения порождённого процесса.
    То есть Вы просто ухудшили ситуацию на один лишний процесс (шелл).
    Код
    if chgrp -R $group $dir; then …
    делал бы то же самое, только без лишнего процесса.

    Вторая проблема состоит в том, что Ваш код вообще делает не то, что вы предполагали, а именно:
    1) Выполняется подстановка `chgrp -R $group $dir`. Сами по себе «бэктики» означают: «выполнить скрипт между ними и вернуть то, что скрипт написал на stdout».
    2) Поскольку chgrp никогда ничего на stdout не пишет, этот скрипт вернёт пустую строку.
    3) Затем выполнится код «()», т.к. в скобки будет поставлена пустая строка. Эта пустая строка будет скриптом, который выполняет сабшелл, организованный при помощи ().
    Поскольку пустая строка — вполне валидный скрипт, это выполняется молча и всегда успешно. Демонстрация:

    #!/bin/sh

    touch /tmp/xyzzy
    if (`chmod 0644 /tmp/xyzzy`); then
    echo A
    else
    echo B
    fi

    if (`chmod 0644 /tmp/xyzzy; echo HEY`); then
    echo A
    else
    echo B
    fi

    и выполнение:

    $ /bin/dash /tmp/foo.sh
    A
    /tmp/foo.sh: 14: HEY: not found
    B

    Короче, как я указал выше, на самом деле Вам следует использовать простое
    if chgrp -R $group $dir; then …



Введите код с картинки