Powershell для замены строки во всех файлах внутри папки

Я пытаюсь запустить сценарий PowerShell, который заменит вхождение строки другой строкой. Я хочу удалить угловые скобки из включения и заменить их двойными кавычками только с именем файла заголовка, без пути к папке перед именем файла заголовка. Пример :

#include <a/b/c/def.hpp>
#include <a/b/c/ddd.hpp> 

к

#include "def.hpp"
#include "ddd.hpp"

Я пробовал это.

(Get-ChildItem -Recurse | Get-Content | Select-String -Pattern "#include <a/b/c/")-replace '#include <a/b/c/(\w+).*/', '#include "'-replace '>','"'

Благодаря этому я получаю желаемый результат, но не могу использовать результат и заменить существующую строку в исходном файле.

Заранее спасибо.

Мне нужно запросить до 100 файлов в папке. Пожалуйста, предложите лучший способ сделать это.

    INPUT 
#include <a0/b/c/d/HeaderFile1.hpp>
#include <a1/b/c/d/HeaderFile2.hpp>
#include <a2/b/c/d/HeaderFile3.hpp>
#include <a3/b/c/d/HeaderFile4.hpp>
#include <a4/b/c/d/HeaderFile5.hpp>
#include <a5/b/c/d/HeaderFile6.hpp>   


OUTPUT
#include "HeaderFile1.hpp"
#include "HeaderFile2.hpp"
#include "HeaderFile3.hpp"
#include "HeaderFile4.hpp"
#include "HeaderFile5.hpp"
#include "HeaderFile6.hpp"

Пожалуйста, проверьте сообщение stackoverflow.com/questions/2837785/…, в нем приведен пример того, как найти и заменить строку в нескольких файлах.

Evandro Paula 09.06.2018 21:31
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
3 141
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Обновлено: проверено на приведенных вами примерах, если формат может отличаться (более глубокий путь, специальные символы в пути и т. д.), Пожалуйста, проверьте перед. И есть резервная копия

Примерно так должно работать:

$items = Get-ChildItem -Recurse
foreach ($i in $items) {
 $newContent = (Get-Content $i) -replace('#include <((\w)+/)*(\w+\.hpp)>','#include "$3"')
 $newContent | Set-Content $i
}

После выполнения вышеуказанной команды он запрашивает ввод. командлет Get-Content в позиции 1 конвейера команд. Укажите значения для следующих параметров: Путь [0]:

SuryaRao 09.06.2018 22:06

@LotPings спасибо за ваш комментарий. Я не забуду сделать это в будущем. Просто поправил и протестировал.

Robert Dyjas 09.06.2018 22:11

@SuryaRao, пожалуйста, проверьте сейчас, я только что исправил и добавил скобки

Robert Dyjas 09.06.2018 22:12

@robdy: шаблон для файла заголовка, например <a/b/c/def.hpp>, не фиксирован. Это также может быть #include <a/b/c/ddd.hpp>. Поэтому мне нужно написать общий запрос.

SuryaRao 09.06.2018 22:17

Мне придется использовать простое регулярное выражение для захвата всех 4 параметров (если я правильно понимаю, что вы хотите заменить, может быть либо #include <a.hpp>, либо #include <b.hpp>, либо #include <c.hpp>, либо #include <def.hpp>). Я только что отредактировал свой исходный ответ, чтобы добавить это

Robert Dyjas 09.06.2018 22:25

@rodby: Позвольте мне объяснить это на примере моих ожиданий. Примечание: a0, a1, a2, a3 в начале. Я хочу удалить угловые скобки из включения и заменить их двойными кавычками только с именем файла заголовка, без пути к папке перед именем файла заголовка. INPUT #include <a0 / b / c / d / HeaderFile1.hpp> #include <a1 / b / c / d / HeaderFile2.hpp> #include <a2 / b / c / d / HeaderFile3.hpp> #include <a3 /b/c/d/HeaderFile4.hpp> ВЫХОД #include "HeaderFile1.hpp" #include "HeaderFile2.hpp" #include "HeaderFile3.hpp"

SuryaRao 09.06.2018 22:39

@LotPings: Я только что отредактировал свой вопрос примером. Надеюсь, это объяснит. Спасибо

SuryaRao 09.06.2018 22:46

Я пробовал следующее, с которым я получаю желаемый результат, но остальное содержимое файла стирается, и изменяется только желаемая строка заголовка. $items = Get-ChildItem -Recurse foreach ($i in $items) { $newContent = ((Get-Content $i) | Select-String -Pattern "#include <a0/b/c/")-replace '#include <a0/b/c/(\w+).*/', '#include "'-replace '>','"' $newContent | Set-Content $i }

SuryaRao 09.06.2018 22:56

Я думаю, что мне удалось построить для него регулярное выражение, проверьте редактирование

Robert Dyjas 09.06.2018 23:09

@robdy: я пробовал регулярное выражение. работает нормально. Благодарю. Можем ли мы также исключить преобразование определенных строк в некоторых случаях здесь, используя регулярное выражение? Пример: Любое включение, которое начинается с «MyFolder», не должно изменять строку заголовка включения. `#include <MyFolder / Myfile.h> 'не следует изменять

SuryaRao 10.06.2018 00:25

Это тоже возможно, но я предлагаю вам приложить некоторые усилия и попробовать это самостоятельно. На ваш первоначальный вопрос уже дан ответ, и, пожалуйста, помните, что мы здесь, чтобы помочь, а не писать за вас весь код. regexr.com - отличное место, чтобы помочь вам (подсказка: может быть полезен отрицательный набор). Удачи!

Robert Dyjas 10.06.2018 08:20

Вам просто нужно записать новый текст обратно в файл. вот мой способ сделать это:

Get-ChildItem -Recurse -File | ForEach-Object {

    (Get-Content $_).replace('#include <a/b/c/def.hpp>','#include "def.hpp"') | Set-Content $_
}

Редактировать:

Теперь, когда вы объяснили свой вопрос, ясно, что вам нужно использовать регулярное выражение. тот, который опубликовал LotPings, будет работать нормально. поэтому, используя его RegEx, правильный ответ:

Get-ChildItem -Recurse -File | ForEach-Object {

    (Get-Content $_)-replace('(?<=#include ).*/([^>]+)>','"$1"') | Set-Content $_
}

Шаблон для файла заголовка, например <a/b/c/def.hpp>, не фиксирован. Это также может быть #include <a/b/c/ddd.hpp>. Итак, мне нужно написать общий запрос

SuryaRao 09.06.2018 22:22

@SuryaRao Не могли бы вы объяснить точно, как выглядят заголовки?

Moshe perez 09.06.2018 22:34

Идея состоит в том, чтобы удалить угловые скобки из строки incude и заменить их двойными кавычками. А также укажите иерархию папок в строке включения.

SuryaRao 09.06.2018 23:02
Ответ принят как подходящий

Я создал несколько тестовых файлов, содержащих ваши образцы:

> Select-String file*.cpp -patt 'hpp'

File1.cpp:1:#include <a0/b/c/d/HeaderFile1.hpp>
File2.cpp:1:#include <a1/b/c/d/HeaderFile2.hpp>
File3.cpp:1:#include <a2/b/c/d/HeaderFile3.hpp>
File4.cpp:1:#include <a3/b/c/d/HeaderFile4.hpp>
File5.cpp:1:#include <a4/b/c/d/HeaderFile5.hpp>
File6.cpp:1:#include <a5/b/c/d/HeaderFile6.hpp>

Следующий скрипт использует RegEx, объясненный в прямом эфире на RegEx101 и ниже static.

## Q:\Test\2018\06\09\SO_50777494.ps1
## the following RegEx usees a positive lookbehind and a
## capture group for the filename.

[RegEx]$Search = '(?<=#include ).*/([^>]+)>'
$Replace = '"$1"'

ForEach ($File in (Get-ChildItem -Path '.\File*.cpp' -Recurse -File)) {
    (Get-Content $File) -Replace $Search,$Replace |
        Set-Content $File
}

Пример вывода Select-String после замены:

> sls file*.cpp -patt 'hpp'

File1.cpp:1:#include "HeaderFile1.hpp"
File2.cpp:1:#include "HeaderFile2.hpp"
File3.cpp:1:#include "HeaderFile3.hpp"
File4.cpp:1:#include "HeaderFile4.hpp"
File5.cpp:1:#include "HeaderFile5.hpp"
File6.cpp:1:#include "HeaderFile6.hpp"

Объяснение RegEx:

(?<=#include ).*/([^>]+)>
  Positive Lookbehind (?<=#include )
  Assert that the Regex below matches
  #include matches the characters #include literally 
  .*
    . matches any character (except for line terminators)
    * Quantifier — Matches between zero and unlimited times, 
      as many times as possible, giving back as needed (greedy)
  / matches the character / literally (case sensitive)
  1st Capturing Group ([^>]+)
    Match a single character not present in the list below [^>]+
    + Quantifier — Matches between one and unlimited times, 
      as many times as possible, giving back as needed (greedy)
  > matches the character > literally (case sensitive)

Другие вопросы по теме