Нужна ли нам задержка между командами в Linux?

(   set -e -- "$(command -v find)"
    [ -x "${1:?}"  ]
    [ ! -e "$1cmd" ]
    [ ! -L "$1cmd" ]
    mv -- "$1"  "$1cmd"
    cat > "$1"
    chmod +x -- "$1"
)   <<""
#!/bin/sh -f
eval '  exec    "$0cmd" '"${1$(                       # f!'"ing colors
        unset   i L O M rt IFS
        chk()   case   ${O+$2}${2--}    in            # $O must be set or $2
                (-maxdepth"$2") M=      ;;            # unset to match "$2$2"
                ([\(!]"$2"|-*"$2")                    # this is the last match
                        printf  %s${1+%b}%.d\
                               "$rt" \\c 2>&-   &&    # printf fails if ! $1  
                        chk(){  ${1+:} exit; }  ;;    # chk() = !!$1 || exit
                (-?*)   shift   $((OPTIND=1))         # handle -[HLP] for 
                        while   getopts :HLP    O     # path resolution w/
                        do      case    $O${L=} in    # NU$L expansions
                                (P)     unset L ;;    # $[HL]=:- $P=-
                                (\?)    rt= chk ''    # opt unexpected  &&
                                        return  ;;    # abandon parse
                        esac;   done;   unset O ;;    # $O is unset until 
                (${M-${O=?*}})                        # above matches fail
                      ! [ ! -L "${L-$2}" ]      ||    # ! -P ||!! -L ||
                        [ !  / -ef "$2"  ]      ||    # !  / == $2   ||
                        rt=$rt' ! \( -path "${'$i'%/}/media/*" -prune \)'
                esac
        while   chk ${1+$((i+=1)) "$1"}               # loop while args remain
        do      printf ' "${'$i}\"                    # printf args to eval
                shift                                 # shift args away
        done                                          # done
)"

Есть сценарий оболочки для find , который вставит несколько аргументов, чтобы запретить реальный find из ищем в / media / , если какой-либо из его аргументов пути равен / .

Вышеупомянутый сценарий состоит из двух частей: это фактический сценарий (который следует за << "" \ n ) и бит установки однократного запуска вверху (это все, что находится между первой совпадающей парой ( скобки ) ) .

install

(   set -e -- "$(command -v find)"         #get /path/to/find
    [ -x "${1:?}"  ]                       #else loudly fail
    [ ! -e "$1cmd" ]                       #fail if /path/to/findcmd
    [ ! -L "$1cmd" ]                       #and double-check
    mv -- "$1"  "$1cmd"                    #rename .../find -> .../findcmd
    cat > "$1"                             #copy stdin to .../find
    chmod +x -- "$1"                       #set new find's executable bit
)   <<"" ###stdin

Бит установки требует небольшого внимания , а не для успешного завершения, если нет разумной возможности сделать это без прямого изменения чего-либо в вашей системе, кроме вашего $ PATH 'd найти имя исполняемого файла - он хочет изменить его с / path / на / find на / path / to / findcmd и попытается, если / путь / к / findcmd еще не существует. Если его тесты подтвердятся - и если у вас есть соответствующие разрешения для применения команд, - он переименует исполняемый файл find и установит на его место новый сценарий оболочки с именем find .

После этого установленный сценарий всегда будет полагаться на переименованный исполняемый файл findcmd , оставшийся там, где он оставил (так что вы, вероятно, захотите сообщить об этом своему менеджеру пакетов, если вы его используете) , и каждый раз, когда он вызывается, он заменяет себя вызываемым $ 0cmd со всеми своими аргументами после того, как взглянет на них.Если вы не сделаете все необходимое, чтобы установка стала постоянной, то в конечном итоге большинство менеджеров пакетов в какой-то момент закончат перезапись установленного сценария недавно обновленным двоичным файлом find , и вы будете прямо там, где вы начали, за исключением того, что у вас также будет более старая find с именем findcmd в системном каталоге ../ bin .

При наличии соответствующих разрешений и при условии, что ваша система не требует каких-либо неуместных сюрпризов, весь сценарий должен иметь возможность самостоятельной установки с копированием и вставкой в ​​приглашение оболочки (хотя вам потребуется выполнить дополнительный RETURN в конце) . Если это не сработает, то, по крайней мере, попытка не должна причинить вреда.

newfind

#!/bin/sh -f
eval '  exec    "$0cmd" '"${1+$(                      # f!'"ing colors
        unset   i L O M rt IFS
        chk()   case   ${O+$2}${2--}    in            # $O must be set or $2
                (-maxdepth"$2") M=      ;;            # unset to match "$2$2"
                ([\(!]"$2"|-*"$2")                    # this is the last match
                        printf  %s${1+%b}%.d\
                               "$rt" \\c 2>&-   &&    # printf fails if ! $1  
                        chk(){  ${1+:} exit; }  ;;    # chk() = !!$1 || exit
                (-?*)   shift   $((OPTIND=1))         # handle -[HLP] for 
                        while   getopts :HLP    O     # path resolution w/
                        do      case    $O${L=} in    # NU$L expansions
                                (P)     unset L ;;    # $[HL]=:- $P=-
                                (\?)    rt= chk ''    # opt unexpected  &&
                                        return  ;;    # abandon parse
                        esac;   done;   unset O ;;    # $O is unset until 
                (${M-${O=?*}})                        # above matches fail
                      ! [ ! -L "${L-$2}" ]      ||    # ! -P ||!! -L ||
                        [ !  / -ef "$2"  ]      ||    # !  / == $2   ||
                        rt=$rt' ! \( -path "${'$i'%/}/media/*" -prune \)'
                esac
        while   chk ${1+$((i+=1)) "$1"}               # loop while args remain
        do      printf ' "${'$i}\"                    # printf args to eval
                shift                                 # shift args away
        done                                          # done
)}"

Мое первое и главное правило при написании сценария-оболочки: отключение . Если бы мне нужна была программа, я бы попытался ее написать, но, поскольку у меня уже есть программа, которую стоит обернуть, я постараюсь позволить ей делать то, что она уже делает, и как можно меньше изменять ее поведение, моя конечная цель. Это означает, что я не должен делать ничего, что могло бы повлиять на среду его выполнения каким-либо образом, не имеющим прямого отношения к цели переноса. Поэтому я не устанавливаю переменные, я не интерпретирую аргументы, я не трогаю потоки ввода-вывода и не изменяю группу процессов завернутой программы или ее родительский pid. В любом случае обертка должна быть максимально непродолжительной и прозрачной.

Приведенный выше сценарий достигает этой цели, в большей степени, чем раньше.Раньше я не был удовлетворен - особенно в отношении решения путей - но я считаю, что обратился к этому. Чтобы сделать это правильно, мне пришлось отслеживать состояние [HLP] , чтобы я мог правильно сравнивать символические ссылки с / , когда одно из -H или Параметры] -L были эффективными, и -P не отменяли их. Если проверка ссылки проходит успешно, текущий аргумент проверяется на соответствие -ef индексного дескриптора файла / -это означает, что практически любое имя для / будет работать (для включения символических ссылок, когда -H или -L эффективны) . Так что я чувствую себя лучше, и я настроил его на блокировку / proc и / sys и / dev из / ] выполняет поиск по умолчанию.

Что он делает особенно хорошо, так это избегание изменения любого из вызываемых состояний перед передачей его в $ 0cmd . Он явно отказывается интерпретировать набор аргументов, который включает любую опцию, которую он не готов обрабатывать, и в этих случаях передает весь набор в $ 0cmd нетронутым, и поэтому, хотя в этих случаях он не может блокировать на поиск пути, он также не влияет на поведение find каким-либо иным образом. Именно по этой причине метод eval "exec wrapped_program $ (arg-handler)" является наиболее предпочтительным для такого рода вещей.

верхний уровень

Фактически, как указано выше, на своем верхнем уровне весь сценарий оболочки представляет собой только одну простую команду, которая сообщает ему о необходимости замены себя другим исполняемым файлом. Любая выполняемая работа выполняется в подоболочке $ ( command substitution ) , и все ее состояние - измененное или нет - полностью локализовано. Цель eval вообще состоит в том, чтобы во второй раз взглянуть на аргументы скрипта без необходимости фактически влиять на них без надобности - и в этом вся суть этой оболочки.

Когда $ ( command sub ) выполнила свою работу, результирующая команда exec 'd будет иметь вид:

exec "$0cmd" "${1}" ... ! \( -path "${[num]%/}/media/*" -prune \) "${2}" ...

... где все ссылки на исходные аргументы - если таковые имеются - даются по порядку и по номеру в их исходной и неизмененной форме (даже нулевые аргументы) в дополнение к шести (! , \ (, -path , "$ {[num]% /} / media / *" , -prune , \) ) вставки, набор которых выполняется для каждого успешного / -ef "$ {num}" теста во время сканирования arg. В противном случае это будет просто:

exec "$0cmd" "${1}" "${2}" "${3}" "${4}" ...

... где все исходные аргументы упоминаются одинаково, без каких-либо вставок.

Таким образом, единственные две возможные модификации, которые эта оболочка может внести в среду своей обернутой цели, таковы:

  • Она изменяет имя процесса со своего собственного на его имя + cmd . Так бывает всегда.

  • Он может вводить шесть аргументов для каждого корневого совпадения в список тех, с которыми он был вызван.

До тех пор, пока первое изменение считается приемлемым (хотя его можно избежать) , здесь есть единственная точка отказа в отношении модификации поведения - а именно, является ли вставка аргумента допустимой. Любые ошибки, иначе связанные с вызовом, просто выходят за рамки и должны обрабатываться целью переноса, и эта оболочка пытается заниматься своим делом.

arg-handler

При подстановке команд я сначала инициализирую переменные, которые нужно отключить, потому что строка "" - лучший способ не сопоставить путь, когда это необходимо. Затем я объявляю функцию chk () , а затем вызываю ее для каждой итерации цикла while , которая увеличивает $ i на единицу для каждого из сценариев аргументы вызова. Он будет печатать каждое приращение $ i , заключенное в кавычки и фигурные скобки, которым предшествуют пробел и знак доллара, в стандартный вывод команды sub:

printf ' "${'$i}\"

...

 "${1}"

Он перебирает вызовы chk () , который получает копию своих аргументов за итерацию, затем сдвигает его, пока не останется ни одного аргумента и цикл не завершится. chk () сравнивает свой аргумент со своими шаблонами и предпринимает соответствующие действия:

  • (- maxdepth "$ 2") M = ;;

    • Когда $ M установлен, последний шаблон может соответствовать только нулевой строке, которая может только не пройти последующие проверки сравнения путей его блока, и поэтому rt = $ rt +! \ ( и т.д. никогда не встречается в этом случае. В противном случае ничего не будет сделано.

    • ] Спецификация POSIX требует, чтобы только - [HL] распознавались перед любыми операндами [... path ...] , а любые другие не указаны. являются операндами [... путь ...] и являются тестовыми операндами:

      Первый операнд и последующие операнды до, но не включая первый операнд, который начинается с - , или ! или (, должны интерпретироваться как [... путь ...] операнды. Если первый операнд начинается с - или является ! или (, поведение не определено. Каждый операнд пути является путевым именем начальной точки в файловой иерархии.

  • ([\ (!] "$ 2" | - * "$ 2 ")

    • Текущий аргумент - это единственный ( левый парен, или ! удар,или он начинается с тире - * , но не равен -maxdepth , и последний шаблон был сопоставлен хотя бы один раз.

    • printf% s $ {1 +% b}%. D "$ rt" \\ c 2> & - &&

      • Запишите значение $ rt - если есть - в команду стандартный выход замещения с последующей успешной записью нулевой длины escape-последовательности \ c % b или неудачным преобразованием в %. d ecimal такой же и той же длины если $ 1 не установлен и достигнут конец аргументов. Этот сбой завершит цикл while .
    • chk () {$ {1+:} выход; }

      • Если printf успешно, то chk () сделал единственную попытку изменить какие-либо аргументы. С этого момента цикл while может продолжать обрабатывать и печатать остальные аргументы, но chk () вообще ничего не будет делать, пока все они не будут исчерпаны, при этом точки, он просто выйдет из подоболочки. И поэтому, как только второй шаблон совпадает хотя бы один раз, ни один из остальных больше никогда не совпадет.
  • (-? *)

    • Текущий аргумент состоит как минимум из двух символов и начинается с тире. Этот шаблон более эксклюзивен, чем шаблон - * "$ 2" над ним один раз $ O , поэтому он может соответствовать только до тех пор, пока не будет найден хотя бы один аргумент не соответствует ему . Таким образом, все начальные параметры будут разделены с помощью getopts и сопоставлены с [HPL] .Если какой-либо начальный параметр не соответствует этому шаблону, функция вызывает себя рекурсивно, чтобы соответствовать шаблону над ним и переопределить chk () . Таким образом, любая последовательность arg, которая не обрабатывается явно, просто дословно передается, и findcmd делает все, что пожелает, с результатами.

    • Для каждой начальной опции, которая соответствует - [HL] , флаговая переменная $ L устанавливается равной пустой строке. И для каждого из тех, которые соответствуют -P , $ L имеет значение не установлено .

  • ($ {M - $ {O =? *}})

    • Первый возникающий аргумент, который не соответствует -? * , вызовет $ O установлен на шаблон ? * . После этого любой из первых двух шаблонов может соответствовать $ {O + $ 2} $ {2 -} . Если когда-либо -maxdepth $ 2 совпадает и M = устанавливается на пустую строку, этот шаблон никогда не сможет снова соответствовать другому ненулевому аргументу, а только одно совпадение второго шаблона требуется прекратить все попытки сопоставления любого из них.

    • Любой ненулевой аргумент, который встречается после первой последовательности параметров - [HLP] и перед другой - * или [\ (?!] аргумент соответствует этому шаблону и проверяется на разрешение пути. Если $ L не задано, то тест !! -L "$ {L- $ 2}" пройдет успешно, если $ 2 является символической ссылкой или недопустимым именем пути, но в противном случае он неизменно терпит неудачу, поскольку никакое имя пути не может соответствовать нулевой строке $ {L =} .

    • Только те аргументы, которые не прошли предыдущий тест, проверяются на ! отменяет совпадение inode с / , и любой аргумент, который не проходит оба теста, приводит к установке $ rt на себя плюс ! \ (-path "$ {[num]% /} / media / * -prune \) строка, которая не записывается до совпадения второго шаблона или до конца аргументов, в зависимости от того, что наступит раньше.

1
08.06.2018, 07:27
1 ответ

No, no es necesario insertar retrasos, no tendrán ningún efecto sobre posibles errores.

Sin embargo, debe verificar si hay errores: la forma más sencilla de hacerlo en los sistemas actuales es agregar

set -e

al comienzo de su script. Consulte la guía de David Pashley para escribir scripts de shell robustos . Sin embargo, tenga en cuenta que set -eno es una panacea, hay diferencias sutiles en el comportamiento según el shell que esté usando .

2
27.01.2020, 23:32

Теги

Похожие вопросы