Чи є спосіб змусити sed запитати мене про підтвердження перед кожною заміною? Щось схоже на "c" при використанні заміни vim.
Сед робить це взагалі?
Чи є спосіб змусити sed запитати мене про підтвердження перед кожною заміною? Щось схоже на "c" при використанні заміни vim.
Сед робить це взагалі?
Відповіді:
Зробити це sed, можливо, не вдасться, оскільки це неінтерактивний редактор потоків. Обгортання sedсценарію вимагатиме занадто багато роздумів. Простіше зробити це за допомогою vim:
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' file.in
Оскільки це було зазначено в коментарях нижче, ось як це буде використано для декількох файлів, що відповідають конкретному шаблону імені файлів у поточному каталозі:
for fname in file*.txt; do
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done
Або, якщо ви спершу хочете переконатися, що файл дійсно містить рядок, що в першу чергу відповідає заданому шаблону, перш ніж проводити заміну,
for fname in file*.txt; do
grep -q 'PATTERN' "$fname" &&
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done
Вищеописані дві петлі оболонки, змінені на findкоманди, які виконують ті самі речі, але для всіх файлів із певним іменем десь у top-dirкаталозі чи під ним ,
find top-dir -type f -name 'file*.txt' \
-exec vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' {} \;
find top-dir -type f -name 'file*.txt' \
-exec grep -q 'PATTERN' {} \; \
-exec vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' {} \;
Або, використовуючи оригінальні петлі оболонки та вводячи findдо них назви шляхів подачі:
find top-dir -type f -name 'file*.txt' -exec sh -c '
for pathname do
vim -c "%s/PATTERN/REPLACEMENT/gc" -c "wq" "$pathname"
done' sh {} +
find top-dir -type f -name 'file*.txt' -exec sh -c '
for pathname do
grep -q "PATTERN" "$pathname" &&
vim -c "%s/PATTERN/REPLACEMENT/gc" -c "wq" "$pathname"
done' sh {} +
Ви ні в якому разі не хочете робити щось подібне for filename in $( grep -rl ... )з тих пір
grepзавершення роботи перед тим, як почати навіть першу ітерацію циклу, яка є неелегантною , іgrepімена шляхів, що повертаються, будуть розділені на слова на пробіли, і ці слова зазнають глобулювання файлів (це дискваліфікує імена шляхів, що містять пробіли та спеціальні символи).Пов'язані:
sedє те, що він може працювати в декількох файлах, наприклад, sed -i 's/old/new/g' /path/to/*.txtабо щось подібне.
for i in $(grep -rl "old"); do vim -c "%s/old/new/gc" -c "wq" "$i"; done
Ви можете отримати це, зробивши таке:
:%s/OLD_TEXT/NEW_TEXT/gc
Зокрема, додавання cпісля третього роздільника.
Зауважте, що опція 'c' працює лише у Vim; ви не зможете ним користуватися sedв командному рядку.
sed.
vim, тому ця відповідь застосовна; однак, явно vim і sed мають різні здібності
Ви можете дозволити sedзробити це все у файлі, а потім зберегти результат у тимчасовий файл, який потім ви можете інтерактивно переламати у вихідний файл, використовуючи sdiff(див. Http://www.gnu.org/software/diffutils/manual/diffutils.html # Invoking-sdiff ):
sed -r 's/something/something_else/g' my_file > tmp_file
sdiff -o my_file -s -d my_file tmp_file
searchandreplace () {
if [ -z $2 ] ; then
realpath * | xargs grep -ins --directories=skip --color=always "$1" | nl -s "."
else
realpath * | xargs grep -ins --directories=skip --color=always "$1" | nl -s "."
exp=$(realpath * | xargs grep -ins --directories=skip --color=never "$1" | cut -d':' -f1,2 | awk -F':' '{print $2 $1}' | sed -E "s|^[0-9]+|sed -i \'&s/|; s|//|/"$1"/"$2"/g\' /|")
IFS=$'\n'
for d in $exp
do
read -p "Exec $(echo -e -n "\033[1;31m$d\033[0m")? " -e REP
if [ "$REP" = y ]; then
echo `bash -c $d`;
fi
done
fi
}
Якщо ви подаєте це одним аргументом - searchandreplace "AAA"- він шукає лише цей рядок у поточному каталозі, але якщо ви подаєте його з подвійними аргументами - searchandreplace AAA BBB- то, крім вищезазначеного, він також просить вас замінити перший на другий рядок на рядок "для кожного рядка.