Все другие решения включают изменение Вашего рабочего процесса или выполнение команды дважды, которая не могла бы подойти, если бы это занимает много времени для выполнения или не повторяемо (например, это удаляет файл - повторное выполнение, это привело бы к другому результату).
Таким образом, вот более сложная идея при необходимости в ней:
.bashrc
exec > >(tee -a ~/$$.out)
PROMPT_COMMAND='LASTLINE=$(tail -n 1 ~/$$.out)'
trap 'rm ~/$$.out' EXIT
подсказка удара
$ python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
/usr/lib/python2.6/dist-packages
$ cd $LASTLINE
$ pwd
/usr/lib/python2.6/dist-packages
Это имеет некоторые проблемы, таким образом, это просто предназначено как начальная точка. Например, выходной файл (~/
) мог бы стать очень большим и заполнить Ваш диск. Кроме того, Ваша целая оболочка могла прекратить работать если tee
умирает.
Это могло быть изменено, чтобы только получить вывод от предыдущего использования команды preexec
и precmd
рычаги в zsh или эмуляция их в ударе, но это более сложно для описания здесь.
Почему бы не использовать энергию?
Откройте все файлы в энергии
vim $(find . -type f)
Или откройте только соответствующие файлы (как предложил Caleb)
vim $(grep 'from' . -Rl)
И действительно затем выполните замену во всех буферах
:bufdo %s/from/to/gc | update
Можно также сделать это с sed
, но мое sed знание ограничено.
Можно сделать что-то сырое с маленьким сценарием Perl, который проинструктирован для выполнения замен линию за линией (-l -pe
) на месте на файлах передал как аргументы (-i
):
perl -i -l -pe '
if (/from/) { # is the source text present on this line?
printf STDERR ("%s: %s [y/N]? ", $ARGV, $_); # display a prompt
$r=<STDIN>; # read user response
if ($r =~ /^[Yy]/) { # if user entered Y:
s/from/to/g; # replace all occurences on this line
}' /path/to/files
Возможные улучшения должны были бы окрасить части подсказки и вещей поддержки как “замена всеми происшествиями в текущем файле”. Отдельно запрос каждого возникновения на строке был бы более трудным.
Вторая часть, соответствуя файлам. если нет слишком многих включенных файлов, и Вы выполняете zsh, можно соответствовать всем файлам в текущем каталоге и его подкаталогах рекурсивно:
perl -i -l -pe '…' **/*(.)
Если Ваша оболочка является ударом ≥4, можно работать perl … **/*
, но это произведет побочные сообщения об ошибках, потому что sed попытается (и сбой) работать на каталогах. Если Вы только хотите выполнить замену в ряде файлов, таких как файлы C, можно ограничить соответствия (который работает или в ударе ≥4 или в zsh):
perl -i -l -pe '…' **/*.[hc]
При необходимости в более прекрасном управлении, по которому файлам Вы заменяете, или Ваша оболочка не имеет рекурсивного каталога, соответствующего конструкции **
, или если Вы имеете слишком много файлов и получаете “командную строку слишком долго” ошибка, использовать find
. Например, для выполнения замены во всех названных файлах *.h
или *.c
в текущем каталоге и его подкаталогах (в более старых системах, Вы, возможно, должны использовать \;
вместо +
в конце строки ( +
форма быстрее, но не доступна везде).
find . -type f -name '*.[hc]' -exec perl -i -l -pe '…' {} +
Однако я придерживался бы интерактивного редактора, если Вам нужно взаимодействие. Gert показал путь к этому в Vim, хотя он требует открытия всех файлов, которые Вы хотите перерыть, который может быть проблемой, если существует много.
В Emacs вот то, как можно сделать это:
M-x find-name-dired
(укажите каталог верхнего уровня), или M-x find-dired
(укажите произвольное find
командная строка).t
отметить все файлы, затем Q
(dired-do-query-replace-regexp
) выполнить замену с запросом на отмеченных файлах. sdiff
(см. http://www.gnu.org/software/diffutils/manual/diffutils.html#Invoking-sdiff ). С его помощью вы можете делать интерактивные исправления. Таким образом, выполнение этого с временным файлом, созданным вами путем выполнения операций замены с использованием sed
, может быть возможным решением:
# use file descriptor 3 to still allow use of stdin
while IFS= read -r -d '' file <&3; do
# write the result of the replacement into a temporary file
sed -r 's/something/something_else/g' -- "$file" > replacer_tmp
if cmp -s -- "$file" replacer_tmp; then
continue; # nothing was replaced
fi
echo "There is something to replace in '$file'! Starting interactive diff."
echo
sdiff -o "$file" -s -d -- "$file" replacer_tmp
echo
done 3< <(find . -type f -print0)
(Файловый цикл с использованием замены процесса, отличного от POSIX, и read -d
как поддерживается, например, bash
.)
grep
вместоfind
так, чтобы Вы только открыли файлы, которые знали соответствия.vim $(grep 'from' . -Rl)
– Caleb 03.05.2011, 20:15