Проблема с getopts и аргументом, содержащим два '*'

Мой скрипт интерпретируется /bin/sh и использует getopts. Когда я делаю :

$ ./check_files.sh -d /tmp -td -x*a*

Аргумент Ma для -x хорошо используется (в конце):

+ find /tmp/geany_socket.9912fb56 /tmp/gpg-OBxSqk /tmp/log /tmp/ssh-bfbl8kSNDM8o /tmp/systemd-private-0a769fff0c124fed8a42ec56733ade46-systemd-timesyncd.service-09Wbx1 /tmp/. /tmp/.. /tmp/.ICE-unix /tmp/.Test-unix /tmp/.X0-lock /tmp/.X11-unix /tmp/.XIM-unix /tmp/.font-unix /tmp/.xfsm-ICE-BILXKY -prune -type d ! -name *a*

Но если я заменю «а» на «я»:

$ ./check_files.sh -d /tmp -td -x*i*

Я получаю это:

+ find /tmp/geany_socket.9912fb56 /tmp/gpg-OBxSqk /tmp/log /tmp/ssh-bfbl8kSNDM8o /tmp/systemd-private-0a769fff0c124fed8a42ec56733ade46-systemd-timesyncd.service-09Wbx1 /tmp/. /tmp/.. /tmp/.ICE-unix /tmp/.Test-unix /tmp/.X0-lock /tmp/.X11-unix /tmp/.XIM-unix /tmp/.font-unix /tmp/.xfsm-ICE-BILXKY -prune -type d ! -name check_files.sh

по уникальной причине у меня есть файл с буквой «i» в имени в моем текущем каталоге, это имя передается команде find (вместо фактического аргумента, который равен *i*. Я тестировал некоторые другие файлы…

У меня нет этой проблемы только с одним '*' в аргументе.

Я пытался использовать простые и двойные кавычки, но я получаю те же результаты.

Кто-нибудь объяснит мне, почему?

Я использую shebang #!/usr/bin/env sh, который вызывает тире. Я также запускал скрипт с bash --posix, у меня другой результат, но все та же проблема, которую я описал выше.

По просьбе @kenorb:

(x)
    SEARCH_NAME_EXCLUDE="${OPTARG}";
(i)
    SEARCH_NAME_INCLUDE="${OPTARG}";
;;

[…]

find_name_clause() {
    if [ -n "$1" ]
    then
    FIND_NAME_CLAUSE=" -name $1 "
    fi
    if [ "$1" -a "$2" ]
        then
            FIND_NAME_CLAUSE="${FIND_NAME_CLAUSE} -a "
        fi    
        if [ -n "$2" ]
        then
            FIND_NAME_CLAUSE="${FIND_NAME_CLAUSE} ! -name  $2 "
        fi    
}

find_name_clause "${SEARCH_NAME_INCLUDE}" "${SEARCH_NAME_EXCLUDE}"
FIND_CLAUSE="${FIND_TYPE_CLAUSE} ${FIND_NAME_CLAUSE}"

[…]


nb_files() {
    NB_FILES=$(find $1 $2 |wc -l)
}

nb_files "${search} ${FIND_CLAUSE}"

person Stéphane    schedule 23.07.2016    source источник
comment
Не могли бы вы поделиться соответствующим кодом вашего скрипта, особенно командой find? Возможно, вам следует запустить скрипт как -x'*a*', так как подстановка расширяется до запуска вашего скрипта.   -  person kenorb    schedule 24.07.2016


Ответы (2)


Установить noglob

set -o noglob

до

./check_files.sh -d /tmp -td -x*a*

или назовите это как

./check_files.sh -d /tmp -td -x\*i\* # -x'*i*' will do the same
person sjsam    schedule 23.07.2016
comment
Он по-прежнему делает то же самое. Возможно, мне придется использовать эту конструкцию в другом месте сценария. - person Stéphane; 24.07.2016
comment
Проблема скорее всего в FIND_NAME_CLAUSE="${FIND_NAME_CLAUSE} ! -name $2 " - person sjsam; 24.07.2016
comment
Предложения @Stéphane Sjsam решают проблему вызова скрипта. Однако сам сценарий также нуждается в доработке. См.: Я пытаюсь поместить команду в переменную, но сложные случаи всегда терпят неудачу!. - person John1024; 24.07.2016
comment
@sjsam: то же самое с FIND_NAME_CLAUSE=${FIND_NAME_CLAUSE}"! -name "$2 - person Stéphane; 24.07.2016
comment
@Stéphane Если вы прочитаете ссылку, которую я оставил, вы увидите, что лучше всего отказаться от того, что вы делаете, и начать использовать массивы заново. - person John1024; 24.07.2016
comment
@Stéphane: Я поддерживаю предложение \@john1024. - person sjsam; 24.07.2016
comment
@ John1024: на самом деле это не решает мою проблему… но в любом случае спасибо, у меня есть указание, что искать. - person Stéphane; 24.07.2016
comment
@Stéphane Что на самом деле не решает мою проблему? Быть конкретной. - person John1024; 24.07.2016
comment
@ John1024 John1024 Я понимаю, что нахожусь в случае 1. документа, который вы указали. Это не сработает так, как я… Я попробую придумать другой способ сделать это :( - person Stéphane; 24.07.2016
comment
@ John1024 John1024, он не говорит мне, как я могу правильно передать аргумент типа *x* (в getopts) и позже объединить его с другой переменной, если x является частью имени файла в моем текущем каталоге. - person Stéphane; 24.07.2016
comment
@Stéphane При передаче аргумента с подстановочными знаками в сценарий аргумент необходимо заключать в кавычки. Ответ Sjsam обсуждается. Когда вы ссылаетесь на аргумент внутри сценария, его необходимо заключать в двойные кавычки. Если у вас есть доступ только к оболочке POSIX, не пытайтесь поместить команду в переменную: заключение переменных в кавычки не работает так, как вам хотелось бы. Если вы можете использовать bash, сделайте это: в нем есть массивы, которые можно использовать для хранения сложных команд. - person John1024; 24.07.2016
comment
В моем сценарии есть еще одна часть, где используется эта переменная: tag="(R${SEARCH_TYPE}i:'${SEARCH_NAME_INCLUDE}'x:'${SEARCH_NAME_EXCLUDE}')", и она работает хорошо. Это подтверждает ваши ответы… - person Stéphane; 24.07.2016
comment
Мой сценарий должен работать без изменений на ksh в какой-то AIX. Поэтому не могу использовать bash. Я знаю, что мне нужно полностью переосмыслить логику, чтобы добиться моего исключения с этими ограничениями, еще раз спасибо. - person Stéphane; 24.07.2016

Мне удалось сделать это так:

find_name_clause() {
        if [ $(expr length $1) -gt 2 ]
        then
            FIND_NAME_CLAUSE=" -name "$1
        fi
        if [ $(expr length $1) -gt 2 -a $(expr length $2) -gt 2  ]
        then
            FIND_NAME_CLAUSE=${FIND_NAME_CLAUSE}" -a "
        fi    
        if [ $(expr length $2) -gt 2  ]
        then
            FIND_NAME_CLAUSE=${FIND_NAME_CLAUSE}"! -name  "$2
        fi    
}

find_name_clause "'"${SEARCH_NAME_INCLUDE}"'" "'"${SEARCH_NAME_EXCLUDE}"'"
person Stéphane    schedule 24.07.2016