UNIX shell и wildcards: проблема

VitMix

Столкнулся с хитрой проблемой.
Задача:
Есть файл, в котором в каждой строке записаны аргументы вызова некоторой утилиты (реально архиватора tar). Например:
-cf /backup/home.foo.tar --exclude *.tmp /home/foo
-cf /backup/www.tar --exclude */log /www

Надо в скрипте на Shell прочитать этот файл и для каждой строчки выполнить утилиту с указанными параметрами.
Если сделать так:
< цикл по строчкам >
read args
tar $args
< /цикл по строчкам >

То Shell заменяет параметры, содержащие '*', на соответствующие списки файлов, что меня не устраивает.
Если написать так:
< цикл по строчкам >
read args
tar "$args"
< /цикл по строчкам >

то звёздочки не заменяются, но зато все параметры передаются как один параметр, что меня тоже не устраивает.
Если в исходном файле с параметрами заэкранировать звёздочки символами '\' или взять в кавычки (двойные или одинарные то результат тоже не тот, который надо, так как все эти символы неизменными доходят до утилиты... Кроме того, усложняется синтаксис исходного файла, что нехорошо.
Я вышел из положения, запретив раскрытие звёздочек вообще (ключ -f)... Но это неправильно, так как где-то в другом месте скрипта раскрытие звёздочек теоретически может понадобиться.
Как правильно решать подобные проблемы?
(Для выполнения скрипта используется /bin/sh из FreeBSD 6.2)

VitMix

Заменил
tar $args

на
/bin/sh -fc "tar $args"

Это выглядит получше...

ermsoft

set -f отключает разворачивание wildcard'ов в шелле.
Hope this helps :)
А, не дочитал до конца... Ну а в чём проблема сделать set +f после цикла?

apl13

То Shell заменяет параметры, содержащие '*', на соответствующие списки файлов, что меня не устраивает.
Как ты думаешь, что будет происходить, если ты просто прилежно наберешь эти строки на клавиатуре, предварив их словом tar?

ermsoft

Насколько я понимаю автора, разница в том, что в интерактивном шелле можно сказать:
tar -cf /backup/home.foo.tar --exclude '*.tmp' /home/foo

, и кавычки съедятся шеллом.
А в приведенной схеме так сделать не получается.

apl13

Зацените, чуваки, чего я нарыл:
$cat 123.c
#include <stdio.h>

int main(int argc, char **argv)
{
printf("%s\t%s\n", argv[1], argv[2]);

return 0;
}

$gcc 123.c
$a.out * abc
123.c a.out
$a.out '*' abc
* abc
$args='* abc' ; a.out $args
123.c a.out
$args="'*' abc" ; a.out $args
'*' abc
$args="'*' abc" ; echo $args | xargs a.out
* abc

VitMix

Оба предложенных решения (set +f и xargs) выглядят неплохо. Про set +f я вообще не знал, а про xargs как-то не подумал...
Всем большое спасибо.
Остановился на варианте:
< цикл по строчкам >
read args
set -f
tar $args
set +f
< /цикл по строчкам >

apl13

set -f
tar $args
set +f
Маза, ИМХО, так:
if [[ $- == *f* ]] ; then set -f ; SETF=1 ; else SETF=0 ; fi
tar $args
[[ $SETF == 1 ]] && set +f

ermsoft

:D
$- нет в POSIX'е, кажется.
Ну и [[ ... ]] точно нет.

apl13

А, забыл.

VitMix

if [[ $- == *f* ]] ; then set -f ; SETF=1 ; else SETF=0 ; fi
tar $args
[[ $SETF == 1 ]] && set +f
Вообще было бы неплохо просто сохранить опции перед

set -f

а потом восстановить их... Есть способ это сделать?

apl13

В баше это $-. В sh - не знаю.

VitMix

В баше это $-. В sh - не знаю.
Насколько я понял, сохранить можно так:

FLAGS="$-"

а вот как восстановить?

apl13

set -${FLAGS}

ermsoft

В баше это $-. В sh - не знаю.
Теоретически максимально портабельно было было бы через set +o (Write the current option settings to standard output in a format that is suitable for reinput to the shell as commands that achieve the same options settings. но:
во-первых, я не могу что-то сходу придумать простого способа (не считая временного файла чтобы это куда-то сохранить и потом воспроизвести (`` съедает переносы строк);
во-вторых, sh (т.е. dash) в моей убунте, например, ведёт себя совсем не по стандарту:
$ set +o
Current option settings
errexit off
noglob off
ignoreeof off
interactive on
monitor on
noexec off
stdin on
xtrace off
verbose off
vi off
emacs off
noclobber off
allexport off
notify off
nounset off
nolog off
debug off
Оставить комментарий
Имя или ник:
Комментарий: