Это ожидаемое поведение.
Флаг -i
/ --in-place
редактирует временную копию файла, а затем перемещает эту копию поверх оригинала.
Итак, когда вы:
sed -i 'bla' symlink
Что делает sed:
sed 'bla' symlink > temp_file
mv temp_file symlink
И, следовательно, уничтожение символической ссылки путем размещения на ее месте обычного файла.
Информация взята из комментария в . Как предотвратить уничтожение символических ссылок sed -i?
С помощью zsh
вы также можете использовать его zmv
функцию автозагрузки:
autoload -Uz zmv # best in ~/.zshrc
zmv -C '(**/)(foo.txt)(#q.)' '${1}bar.txt'
или:
zmv -C '**/foo.txt(#q.)' '$f:h/bar.txt'
Преимущество использования zmv
по сравнению с написанием цикла вручную состоит в том, что он имеет несколько проверок безопасности, которые предотвращают необратимые ошибки.
Есть несколько вариантов:
find rootdir -type f -name foo.txt -execdir cp {} bar.txt \;
Это ищет обычные файлы с именем foo.txt
в любом месте или под rootdir
, и когда он найден, cp
используется для его копирования с именем bar.txt
в том же каталоге. Опция -execdir
не является стандартной -, но обычно реализуется и запускает данную утилиту в каталоге, где был найден файл. {}
будет заменено именем найденного файла.
Как вариант,
find rootdir -type f -name foo.txt -exec sh -c '
for pathname do
cp "$pathname" "${pathname%/*}/bar.txt"
done' sh {} +
Это делает в основном то же самое, но вызывает короткий скрипт в -строке sh -c
с пакетами найденных foo.txt
файлов. cp
в цикле скопирует каждый из них в тот же каталог, что и найденный файл, но с заменой имени файла на bar.txt
.
Используя **
, как вы упомянули в вопросе (, предполагая оболочку bash
):
shopt -s globstar nullglob dotglob
for pathname in rootdir/**/foo.txt; do
cp "$pathname" "${pathname%/*}/bar.txt"
done
В bash
установка параметра оболочки globstar
позволяет использовать **
для рекурсивного сопоставления с подкаталогами, а dotglob
позволяет шаблонам также сопоставлять скрытые имена. Параметр оболочки nullglob
приводит к полному исчезновению шаблонов, а не их раскрытию в случае отсутствия соответствия.
Опять же, но сzsh
(явным запросом обычных файлов и включением эквивалентной обработки подстановки, как dotglob
и nullglob
дляbash
):
for pathname in rootdir/**/foo.txt(.ND); do
cp $pathname $pathname:h/bar.txt
done
Здесь $pathname:h
будет таким же, как $pathname
, но с удаленной частью имени файла из пути(:h
как в «только голове», а не в конце бита ).