Czy ktoś może zasugerować elegancki sposób na osiągnięcie tego?
Wejście:
test instant ()
test instant ()
...
test instant () //total 1000 lines
wyjście powinno być:
test instant1 ()
test instant2 ()
test instant1000()
Puste wiersze znajdują się w moich plikach wejściowych i w tym samym katalogu jest wiele plików, które muszę przetworzyć jednocześnie.
Próbowałem zastąpić wiele plików w tym samym katalogu i nie działałem.
for file in ./*; do perl -i -000pe 's/instance$& . ++$n/ge' "$file"; done
błędy:
Substitution replacement not terminated at -e line 1.
Substitution replacement not terminated at -e line 1.
i próbowałem również:
perl -i -pe 's/instant/$& . ++$n/ge' *.vs
Działało, ale indeks ciągle zwiększał się z jednego pliku do drugiego. Chciałbym zresetować to do 1 po zmianie na nowy plik. Jakieś dobre sugestie?
find . -type f -exec perl -pi -e 's/instant/$& . ++$n{$ARGV}/ge' {} +
działa, ale zastąpił wszystkie inne pliki nie powinny być zastępowane. Wolę po prostu zastąpić pliki *.txt
tylko.
test instant ()
?Odpowiedzi:
lub z GNU
awk
:Aby edytować pliki w miejscu, dodaj
-i
opcję doperl
:Lub rekurencyjnie:
Objaśnienia
-p
polega na przetwarzaniu danych wejściowych linia po linii, ocenieniu wyrażenia przekazanego-e
dla każdej linii i wydrukowaniu go. Dla każdej linii podstawiamy (za pomocąs/re/repl/flags
operatora)instant
samą siebie ($&
) i przyrostową wartość zmiennej++$n
.g
Flaga jest, aby zmiany globalnie (nie tylko raz), ae
więc, że wymiana jest interpretowany jako perl kod do e wycenić (nie stałą string).W przypadku edycji w miejscu, gdzie jedno wywołanie Perla przetwarza więcej niż jeden plik, chcemy
$n
zresetować każdy plik. Zamiast tego używamy$n{$ARGV}
(gdzie$ARGV
jest aktualnie przetwarzany plik).Ten
awk
zasługuje na trochę wyjaśnienia.Korzystamy ze zdolności GNU
awk
do oddzielania rekordów na dowolnych ciągach (nawet wyrażeniach regularnych). Za pomocą-vRS=instant
ustawiamy separator r̲ecord nainstant
.RT
jest zmienną, która przechowuje to, co zostało dopasowaneRS
, więc zazwyczaj,instant
z wyjątkiem ostatniego rekordu, w którym będzie to pusty ciąg. W danych wejściowych powyżej record ($0
) i terminatorami record (RT
) są ([$0|RT]
):Więc wszystko, co musimy zrobić, to wstawić liczbę rosnącą na początku każdego rekordu, z wyjątkiem pierwszego.
Co robimy powyżej. Dla pierwszego rekordu
n
będzie pusty. Ustawiamy ORS (parametr wyjściowy rordecord s̲eparator ) na RT, abyawk
drukowałn $0 RT
. Robi to na podstawie drugiego wyrażenia (++n
), które jest warunkiem, który zawsze zwraca wartość true (liczba niezerowa), a zatem$0 ORS
dla każdego rekordu wykonywana jest domyślna akcja (drukowania ).źródło
sed
naprawdę nie jest najlepszym narzędziem do pracy, potrzebujesz czegoś o lepszych możliwościach skryptowych. Oto kilka opcji:perl
Te
-p
środki „wydrukować każdą linię” po zastosowaniu co skrypt jest podane z-e
. Te-00
zakręty w trybie „ustęp” So rekordów (wierszy) są definiowane przez kolejny znak nowej linii (\n
) znaków, to pozwala poradzić sobie z podwójnymi rozstawionych linii poprawnie.$&
jest ostatnim dopasowanym wzorcem i$.
jest bieżącym numerem wiersza pliku wejściowego. Funkcjae
ins///e
pozwala mi oceniać wyrażenia w operatorze podstawienia.awk (zakłada to, że twoje dane są dokładnie takie, jak pokazano, z trzema polami oddzielonymi spacjami)
Tutaj zwiększamy
k
zmiennąk
tylko wtedy, gdy bieżący wiersz nie jest pusty,/./
w którym to przypadku drukujemy również niezbędne informacje. Puste linie są drukowane bez zmian.różne muszle
Tutaj każdy wiersz wejściowy jest automatycznie dzielony na białe znaki, a pola są zapisywane jako
$a
,$b
i$c
. Następnie w pętli,$c
jest zwiększona o jeden dla każdej linii, dla których$a
nie jest pusty i jest aktualna wartość zostanie wydrukowany obok drugiego pola$b
.UWAGA: wszystkie powyższe rozwiązania zakładają, że wszystkie wiersze w pliku mają ten sam format. Jeśli nie, odpowiedź @ Stephane jest właściwą drogą.
Do obsługi wielu plików i zakładania, że chcesz to zrobić dla wszystkich plików w bieżącym katalogu, możesz użyć tego:
OSTROŻNIE: To zakłada proste nazwy plików bez spacji, w razie potrzeby do czynienia z czymś bardziej złożonym, przejdź do (zakładając
ksh93
,zsh
albobash
):źródło
Jeśli chcesz rozwiązać ten problem,
sed
możesz użyć czegoś takiegobash
:lub bardziej przenośnym rozwiązaniem byłoby:
źródło