Синтаксис сравнения строк Bash - PullRequest
0 голосов
/ 06 августа 2009

Я просматривал скрипт /etc/bash_completion, найденный в некоторых пакетах Debian. Мне было интересно использовать код, который просматривает определенную директорию (/etc/bash_completion.d/ по умолчанию) и получает все файлы в этой директории.

К сожалению, попытка запустить скрипт вызывает ошибки в версии bash для Mac OS X. Рассматриваемые строки:

for i in $BASH_COMPLETION_DIR/*; do
    [[ ${i##*/} != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|.rpm*) ]] &&
    [ \( -f $i -o -h $i \) -a -r $i ] && . $i
done

В частности, моя версия bash (3.2.17) блокирует конструкцию @(). Я понял, что цель этого первого теста - убедиться, что мы не получаем никаких файлов подкачки редактора или резервных копий и т. Д. Я хотел бы точно понять, что делает этот синтаксис @(), и, если возможно, как получить что-то похоже (и так же элегантно) работает на моей древней копии Bash. Кто-нибудь может предложить понимание?

1 Ответ

3 голосов
/ 06 августа 2009

Это просто расширение для сравнения оболочек, которое эквивалентно grep "или" оператору (|).

В зависимости от вашей версии bash, она может быть недоступна или вам может потребоваться установить extglob со встроенным shopt. Смотрите следующую стенограмму сессии:

    pax@daemonspawn> $ bash --version
        GNU bash, version 3.2.48(21)-release (i686-pc-cygwin)
        Copyright (C) 2007 Free Software Foundation, Inc.
    pax@daemonspawn> echo @(*~|*.pl)
        bash: syntax error near unexpected token '('
    pax@daemonspawn> shopt extglob
        extglob off
    pax@daemonspawn> shopt -s extglob
    pax@daemonspawn> echo @(*~|*.pl)
        qq.pl qq.sh~ xx.pl
    pax@daemonspawn> 

Это позволяет работать следующим образом:

    ?(pattern-list)
        Matches zero or one occurrence of the given patterns
    *(pattern-list)
        Matches zero or more occurrences of the given patterns
    +(pattern-list)
        Matches one or more occurrences of the given patterns
    @(pattern-list)
        Matches one of the given patterns
    !(pattern-list)
        Matches anything except one of the given patterns

Если вы не можете заставить его работать с shopt, вы можете создать аналогичный эффект с помощью более старых методов, таких как:

    #!/bin/bash
    for i in $BASH_COMPLETION_DIR/*; do
        # Ignore VIM, backup, swp, files with all #'s and install package files.
        # I think that's the right meaning for the '\#*\#' string.
        # I don't know for sure what it's meant to match otherwise.

        echo $i | egrep '~$|\.bak$|\.swp$|^#*#$|\.dpkg|\.rpm' >/dev/null 2>&1
        if [[ $? == 0 ]] ; then
            . $i
        fi
    done

В качестве альтернативы, если есть несколько сложных определений, которые будут определять, хотите ли вы, чтобы он был получен, вы можете использовать переменную doit, которая изначально установлена ​​на true, и установить ее на false, если какое-либо из этих условий срабатывает. Например, следующий скрипт qq.sh:

    #!/bin/bash
    for i in * ; do
        doit=1

        # Ignore VIM backups.
        echo $i | egrep '~$' >/dev/null 2>&1
        if [[ $? -eq 0 ]] ; then
            doit=0
        fi

        # Ignore Perl files.
        echo $i | egrep '\.pl$' >/dev/null 2>&1
        if [[ $? -eq 0 ]] ; then
            doit=0
        fi

        if [[ ${doit} -eq 1 ]] ; then
            echo Processing $i
        else
            echo Ignoring $i
        fi
    done

сделал это в моем домашнем каталоге:

    Processing Makefile
    Processing binmath.c
    : : : : :
    Processing qq.in
    Ignoring qq.pl    --+
    Processing qq.sh    |
    Ignoring qq.sh~   --+--- see?
    Processing qqin     |
    : : : : :           |
    Ignoring xx.pl    --+
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...