Из комментариев получаю что-то похожее типа это твоя команда:
find -type f -mtime +14 -mtime -22 -iname '*.xml' | while IFS= read -f x; do xmlstarlet sel -T -t -v '//magicElement' -n "$x" | grep -q magicValue && echo "$x"; done
Вместо конвейера в циклwhile
-вы можете использовать -exec sh -c '...'
для фильтрации файлов:
find -type f -mtime +14 -mtime -22 -iname '*.xml' \
-exec sh -c 'xmlstarlet sel -T -t -v "//magicElement" "$1" | grep -q magicValue' find-sh {} \; \
-exec vi -- {} +
Попробуйте:
Рассмотрим три файла:
.
├── a:<magicElement>magicValue</magicElement>
├── b:<magicElement>magicValue</magicElement>
└── c:<magicElement>someOtherValue</magicElement>
$ find. -type f \
-exec sh -c 'xmlstarlet sel -T -t -v "//magicElement" "$1" | grep -q magicValue' find-sh {} \; \
-exec echo vi -- {} +
Выход:
vi --./a./b
Если ваш vi поддерживает это (и, если ваш vi — это vim, он поддерживает ), вы можете использовать список быстрых исправлений. Это функция, которая сохраняет имена файлов -1 в списке с возможностью навигации. Важными командами являются :cnext
и :cprev
, эквивалентные :next
и :prev
для записей быстрых исправлений. Многие другие, такие как :cfile
, :cfirst
, :clast
и :copen
, также существуют.
Итак, возникает вопрос, как загрузить файлы в список быстрых исправлений? Вот несколько вариантов:
vi -q <file>
:список быстрых исправлений будет установлен на основе файла. Но если вы попробуете это, где файл содержит, например, Netherlands/Purge (GDPR) 2020-01-09.txt
Netherlands/Purge (GDPR) 2020-01-27.txt
Switzerland/New mailing 2020-01-27.txt
Вы будете разочарованы. По умолчанию 'errorformat'
, который указывает vi, как анализировать имена файлов -из сообщений об ошибках, установлен для компиляторов C. Итак, вам понадобится
vi --cmd 'set errorformat=%f' -q <file>
Существует несколько способов создания <file>
; один pipeline... >errors
. Но тогда вы должны удалить файл.
Более интересным, если ваша оболочка поддерживает это, является
vi --cmd 'set errorformat=%f' -q <(pipeline)
:cexpr
с функцией system()
:загрузите vi и выполните команды set errorformat=%f
cexpr system('pipeline')
Это похоже на версию с командной строкой, но включает дополнительный шаг и более сложную команду.Это более полезно, если вы уже находитесь в vi, когда вам нужно установить список быстрых исправлений (, хотя в этот момент я мог бы просто сделать
:args `pipeline`
предполагая, что это не разбивается на пробелы, и меня не волнует текущий список аргументов ).
Часто имена файлов -сочетаются с номерами строк или столбцов, а иногда даже с сообщениями, например, от компилятора. :help quickfix
для получения дополнительной информации.
Если вы часто делаете подобные вещи, вам может понравиться эта функция оболочки:
vq () {
if (($# > 0)); then
vim -q <("$@" 2>&1)
else
printf '%s\n' 'Usage: vq cmd' '' 'Use {cmd} output as quickfix list'
fi
}
Вы предоставляете одну команду (часто grep
или тому подобное )до vq
, и она делает все остальное; но это работает только в том случае, если вывод команд соответствует стандартному 'errorformat'
. Однако настройка 'errorformat'
после загрузки списка быстрых исправлений должна работать.
Вот два уродливых приема, которые я использовал годами для решения этой проблемы. оба требуют X.
find... -print0|...| xargs -0r gvim -f
find... -print0|...| xargs -0r xterm -e vim
Это работает даже через ssh.
Поскольку вы находитесь в Баше,
#!/bin/bash
readarray -d '' -t files < <(find path -type f -print0)
vi -- "${files[@]}"
Замените find path -type f -print0
вашим фактическим конвейером.
Хотя в ваших файлах нет новых строк, поддержка таких имен файлов была добавлена пользователем glenn jackman .
Чтобы использовать вкладки вместо буферов для vi
, добавьте флаг -p
:vi -p...
.
Если конвейер не требовался, можно было просто использовать опцию -exec
:
find path -type f -exec vi -- {} +
Unfortunately this does not work when mycommand is an editor because although xargs can assemble the set of files to edit, stdin is already taken up from the pipeline and I can't see a way to run an editor in-place.
Этот способ задокументирован на странице руководства для GNU Findutilsxargs
:
-o, --open-tty
Reopen stdin as /dev/tty in the child process before executing
the command. This is useful if you want xargs to run an inter‐
active application.
Чтобы можно было использовать
find. -name 'pattern' -print0 | xargs -0o vim
Однако это новая функция. Я не вижу этого в более старой системе с xargs 4.4.2; Я вижу это в Ubuntu 18, где есть xargs 4.7.0.
Сейчас у xargs
, возможно, не было опции -o
десять лет назад, но подстановка процесса Bash существовала десять лет назад, и у xargs
есть опция -a
для чтения из файла вместо стандартного ввода.
Таким образом, задача решается без xargs -o
вот так:
xargs -0 -a <(find. -name 'pattern' -print0) vim
Поскольку xargs
читает из (то, что он считает )файлом, полученным в качестве аргумента, он оставил стандартный ввод в покое.