Запуск `exec` із вбудованою Bash


9

Я визначив функцію оболонки (назвемо її так clock), яку я хочу використовувати як обгортку для іншої команди, подібної до timeфункції, наприклад clock ls -R.

Моя функція оболонки виконує деякі завдання, а потім закінчується exec "$@".

Я хотів би, щоб ця функція працювала навіть із вбудованими оболонками, наприклад, clock time ls -Rповинна виводити результат timeвбудованого, а не /usr/bin/timeвиконуваного файлу. Але execзавжди замість цього виконується команда.

Як змусити функцію Bash працювати як обгортку, яка також приймає вбудовані оболонки як аргументи?

Редагувати : Я щойно дізнався, що timeце не вбудований Bash, а спеціальне зарезервоване слово, пов’язане з трубопроводами. Мені все ж цікаво рішення для вбудованих модулів, навіть якщо воно не працює time, але більш загальне рішення було б ще краще.


Потрібно викликати оболонку прямо, використовуючи exec bash -c \' "$@" \'. Якщо ваша команда в першому параметрі не буде розпізнана як сценарій оболонки, вона буде інтерпретуватися як двійковий, який безпосередньо запускається. Крім того, і простіше, просто пропустіть execта зателефонуйте "@"зі своєї оригінальної оболонки.
AFH

Відповіді:


9

Ви визначили функцію bash. Отже, ви вже перебуваєте в оболонці bash, коли викликаєте цю функцію. Тож ця функція може просто виглядати так:

clock(){
  echo "do something"
  $@
}

Ця функція може бути використана за допомогою вбудованих bash, спеціальних зарезервованих слів, команд, інших визначених функцій:

Псевдонім:

$ clock type ls
do something
ls is aliased to `ls --color=auto'

Баш вбудований:

$ clock type type
do something
type is a shell builtin

Ще одна функція:

$ clock clock
do something
do something

Виконавчий файл:

$ clock date
do something
Tue Apr 21 14:11:59 CEST 2015

Чи є в цьому випадку різниця між запуском $@і exec $@, якщо я знаю, я виконую фактичну команду?
анол

3
Під час використання execкоманда замінює оболонку. Отже, більше немає вбудованих псевдонімів, спеціальних зарезервованих слів, визначених слів, тому що виконуваний файл виконується за допомогою системного виклику execve(). Цей системний виклик очікує виконуваний файл.
хаос

Але, з точки зору зовнішнього спостерігача, чи все-таки їх можна розрізнити, наприклад, при цьому exec $0існує єдиний процес, тоді як $@все ще є два.
анол

4
Так, $@має запущену оболонку як батьківську і команду як дочірній процес. Але коли ви хочете використовувати вбудовані, псевдоніми тощо, ви повинні зберегти оболонку. Або почати нове.
хаос

4

Єдиний спосіб запустити ключове слово вбудований у оболонку або оболонку - це запустити нову оболонку, оскільки exec "замінює оболонку даною командою". Свій останній рядок слід замінити на:

IFS=' '; exec bash -c "$*"

Це працює як з вбудованими, так і з зарезервованими словами; принцип той самий.


3

Якщо обгортці потрібно вставити код перед даною командою, псевдонім буде працювати, оскільки вони розгорнуті на дуже ранній стадії:

alias clock="do this; do that;"

Псевдоніми майже буквально вставляються замість псевдонімічного слова, тому ;важливо відстежувати значення - воно змушує clock time fooрозширюватися do this; do that; time foo.

Ви можете зловживати цим, щоб створити магічні псевдоніми, які навіть обходять цитування.


Для вставки коду після команди ви можете використовувати гачок "DEBUG".

shopt -s extdebug
trap "<code>" DEBUG

Конкретно:

shopt -s extdebug
trap 'if [[ $BASH_COMMAND == "clock "* ]]; then
          eval "${BASH_COMMAND#clock }"; echo "Whee!"; false
      fi' DEBUG

Гак все ще працює перед командою, але, коли він повертається, falseвін каже bash скасувати виконання (тому що гачок вже запустив його через eval).

В якості іншого прикладу ви можете використовувати цей псевдонім command pleaseдля sudo command:

trap 'case $BASH_COMMAND in *\ please) eval sudo ${BASH_COMMAND% *}; false; esac' DEBUG

1

Єдиним рішенням, до якого я міг придумати, було б провести аналіз випадку, щоб визначити, чи є перший аргумент командою, вбудованим чи ключовим словом, а в останньому випадку - помилкою:

#!/bin/bash

case $(type -t "$1") in
  file)
    # do stuff
    exec "$@"
    ;;
  builtin)
    # do stuff
    builtin "$@"
    ;;
  keyword)
    >&2 echo "error: cannot handle keywords: $1"
    exit 1
    ;;
  *)
    >&2 echo "error: unknown type: $1"
    exit 1
    ;;
esac

timeОднак це не вдається , тому може бути краще (і стисліше) рішення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.