Как показать последнюю команду с расширяющейся функцией в ударе

С ударом (только начиная с версии 4.0) можно сделать это:

shopt -s globstar
wc -l **/*.php

В zsh можно всегда делать wc -l **/*.php.

3
22.09.2013, 02:02
2 ответа

Более нормальная версия @slm:

find-grep() {
  cmd=(find . -type f -name "$1" -exec grep "$2" {})
  printf '%q ' "${cmd[@]}"
  printf '+\n'
  "${cmd[@]}" +
}

(никакая потребность в каналах или xargs здесь) Или:

find-grep () (
  set -x
  find . -type f -name "$1" -exec grep "$2" {} +
)

(отметьте () вместо {} запустить подоболочку для ограничения объема set -x. Обратите внимание, что это не заставляет больше процессов быть разветвленным, это просто что fork для процесса, который выполнится find сделан ранее).

Помните, что необходимо заключить подстановочные символы в кавычки, таким образом, они не расширены оболочкой:

find-grep '*.c' pattern

Если вместо этого, Вы хотите, чтобы это было продвинуто к истории, так, чтобы Вы видели расширенную команду при нажатии клавиши Up Вы могли записать это:

find-grep() {
  cmd=$(printf '%q ' find . -type f -name "$1" -exec grep "$2" {})+
  history -s "$cmd"
  eval "$cmd"
}
2
27.01.2020, 21:20
  • 1
    Спасибо за более правильную версию. Каково преимущество cmd = (...) по сравнению с cmd= $ "..." кроме, он более читаем? Также, почему не может + быть включенными в присваивание массива? –  slm♦ 21.09.2013, 15:39
  • 2
    @slm, $"..." для локализации, она не имеет смысла в этом контексте. Вам нужны массивы для отслеживания то, что аргументы или заключение в кавычки использования. + не включен для предотвращения конечного пробела. –  Stéphane Chazelas 21.09.2013, 15:47

Вот один способ сделать это:

$ find-grep () {
  cmd=(find . -type f -name \"$1\" -print0 \| xargs -0 grep \"$2\")
  printf "%s\n" "${cmd[*]}" 
  eval "${cmd[*]}"
}

Пример

Вот некоторые демонстрационные данные.

$ ls -l
total 8
-rw-rw-r-- 1 saml saml 4 Sep 21 10:44 1.c
-rw-rw-r-- 1 saml saml 4 Sep 21 10:44 2.c
-rw-rw-r-- 1 saml saml 0 Sep 21 10:22 3.c
-rw-rw-r-- 1 saml saml 0 Sep 21 10:22 4.c
-rw-rw-r-- 1 saml saml 0 Sep 21 10:22 5.c

Вот наша функция в действии, 2 из файлов содержат строку "нечто".

$ find-grep '*.c' "foo"
find . -type f -name "*.c" -print0 | xargs -0 grep "foo"
./2.c:foo
./1.c:foo

Объяснение

Эта конкретная версия Вашей функции делает следующие вещи по-другому.

  1. Мы определяем переменную с Вашей командой, $cmd=(find....). Команда перенесена в массив, (..).
  2. Мы повторяем созданный массив $cmd использование printf. Мы передаем элементы массива с помощью * нотация, ${cmd[*]}, так, чтобы мы получили массив как единственную строку, а не как дискретный список элементов.
  3. Наконец мы оцениваем массив $cmd, который выполняет его.

Другой подход

Вы могли также перенести функцию как это: set -x ...function... set +x, который имеет эффект включения отладки только на время ...function..., и затем выключение его.

$ find-grep () { 
  set -x
  find . -type f -name "$1" -print0 | xargs -0 grep "$2"
  set +x
}

Пример

$ find-grep *.c foo
+ find . -type f -name '*.c' -print0
+ xargs -0 grep foo
+ set +x

Этот подход не столь легко считать, но он показывает Вам те же грубые функции, просто разбитые на основе того, как они выполнялись. Сначала find ..., сопровождаемый xargs ....

2
27.01.2020, 21:20
  • 1
    Спасибо slm! Я использовал бы этот путь. Это в порядке, если я понимаю, что нет никакого простого способа развернуть строку find-grep *.c foo к исходной команде, если функция не определяется как это? –  ironsand 21.09.2013, 05:58
  • 2
    @Tetsu - Я обеспечил альтернативный метод. Я не могу думать о другом способе сделать это. –  slm♦ 21.09.2013, 06:05
  • 3
    Это не будет работать правильно, если аргументы будут содержать несколько специальных символов оболочки, которые будут обычно иметь место, поскольку это предназначено для взятия шаблонов (который OP забыл заключать в кавычки (*.c)) и regexps. спасибо –  Stéphane Chazelas 21.09.2013, 11:38
  • 4
    @StephaneChazelas - попробованный для обращения к некоторым точкам, если Вы получаете секунду, смотреть и сообщают мне, делает ли она так, Спасибо! –  slm♦ 21.09.2013, 18:57
  • 5
    Вам не нужен массив при передаче командной строки eval. Однако Вам нужно, должен выйти из всех специальных символов в 1$ и 2$ (и необходимо заключить переменные в кавычки как всегда). Помещение двойных кавычек вокруг них работа привычки. Если $1 '*"*' например, или 2$ '', that won't be enough. Hence the printf %q' в решении я дал. –  Stéphane Chazelas 21.09.2013, 20:07

Теги

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