2011-08-05 16 views
7

pliku muszę zmodyfikować zawiera następujące elementy:Substytucja Sed możliwa z arytmetyką?

block: 16, size: 16, start: 8, length: 4 

Chciałbym plik tak, że wartości dla bloku, rozmiarze zostanie podzielona przez 2, podczas gdy wartości dla początku, długość zostanie pomnożona przez 2.

Ponieważ muszę wprowadzić takie modyfikacje dla całej gamy plików, rozważam użycie Sed, aby wykonać pracę zastępczą dla mnie. Ale nie jestem pewien, czy w procesie dopasowywania i zastępowania dozwolone są obliczenia.

Odpowiedz

8

Zawsze próbuję rozwiązać każdy problem oznaczony przy użyciu sed. Ale tutaj byłoby tak łatwo osiągnąć to, co próbujesz zrobić z awk. (I stosowanie sed w tym przypadku jest zbyt trudne.) Więc tutaj jest moje rozwiązanie używając awk:

$ echo "block: 16, size: 16, start: 8, length: 4" | awk '{ 
    printf "%s %d, %s %d, %s %d, %s %d\n", $1, $2/2, $3, $4/2, $5, $6*2, $7, $8*2 
}' 
block: 8, size: 8, start: 16, length: 8 
+1

To nie działa zgodnie z oczekiwaniami, gdy kolejność wpisów jest inna, np. sol. '" block: 16, start: 8, rozmiar: 8, długość: 4 "' –

0

Nie myśl, że to możliwe. Zobacz np. http://www.delorie.com/gnu/docs/sed/sed_15.html.

Jeśli jednak dysponujesz tylko niewielkim zestawem możliwych wartości dla bloku, rozmiaru, początku i długości, najszybsze może być zakodowanie wymaganych zastępstw. Następną, najprostszą opcją jest prawdopodobnie użycie awk, ale to nie może modyfikować plików w miejscu.

5

Perl jest przydatna tutaj:

perl -pe ' 
    s{(\D+)(\d+)(\D+)(\d+)(\D+)(\d+)(\D+)(\d+)} 
    {$1 . $2/2 . $3 . $4/2 . $5 . $6*2 . $7 . $8*2}e 
' file 

Jeśli chcesz edytować swoje pliki -place, perl ma opcję -i jak sed.

+1

Masz na myśli to, że * sed * ma opcję '-i' jak * perl *, a nie odwrotnie. Nie znajdziesz opcji '-i' na wymaganej liście opcji w POSIX spec dla * sed *, BTW, ale raczej tylko sporadycznie i nieoficjalnie w niektórych portach dostawców. READ: 'sed -i' ** nie jest powszechnie obsługiwany **, chociaż' perl -i' jest. – tchrist

5

(Odpowiednim narzędziem do tego celu jest awk, ale dla zabawy sed ćwiczenia ...)

Jest to możliwe w sed. Po tym wszystkim, mnożenie przez 2 jest podstawienia ostatniej cyfry według prostych reguł:

  • 0 -> 0
  • 1 -> 2
  • 2 -> 4
  • 3 -> 6
  • ...
  • 8 -> 16
  • 9 -> 18

Aby zadbać o cyfrę carry, każdą regułę należy zapisać dwukrotnie.

Ten sed skrypt, który można uruchomić z sed -f script, wykonać mnożenie przez 2 wszystkich numerów na liniach wejściowych:

s/$/\n\n/ 
:loop 
s/0\n1\n/\n\n1/;t loop 
s/0\n\n/\n\n0/;t loop 
s/1\n1\n/\n\n3/;t loop 
s/1\n\n/\n\n2/;t loop 
s/2\n1\n/\n\n5/;t loop 
s/2\n\n/\n\n4/;t loop 
s/3\n1\n/\n\n7/;t loop 
s/3\n\n/\n\n6/;t loop 
s/4\n1\n/\n\n9/;t loop 
s/4\n\n/\n\n8/;t loop 
s/5\n1\n/\n1\n1/;t loop 
s/5\n\n/\n1\n0/;t loop 
s/6\n1\n/\n1\n3/;t loop 
s/6\n\n/\n1\n2/;t loop 
s/7\n1\n/\n1\n5/;t loop 
s/7\n\n/\n1\n4/;t loop 
s/8\n1\n/\n1\n7/;t loop 
s/8\n\n/\n1\n6/;t loop 
s/9\n1\n/\n1\n9/;t loop 
s/9\n\n/\n1\n8/;t loop 
s/\n1\n/\n\n1/;t loop 
s/\(.\)\n\n/\n\n\1/;t loop 
s/^\n\n// 

Dzielenie parzystą liczbę przez 2, jest taka sama logika, ale z od lewej do prawej zamiast z prawej do lewej:

s/^/\n\n/ 
:loop 
s/\n1\n0/5\n\n/;t loop 
s/\n\n0/0\n\n/;t loop 
s/\n1\n1/5\n1\n/;t loop 
s/\n\n1/\n1\n/;t loop 
s/\n1\n2/6\n\n/;t loop 
s/\n\n2/1\n\n/;t loop 
s/\n1\n3/6\n1\n/;t loop 
s/\n\n3/2\n1\n/;t loop 
s/\n1\n4/7\n\n/;t loop 
s/\n\n4/2\n\n/;t loop 
s/\n1\n5/7\n1\n/;t loop 
s/\n\n5/2\n1\n/;t loop 
s/\n1\n6/8\n\n/;t loop 
s/\n\n6/3\n\n/;t loop 
s/\n1\n7/8\n\n/;t loop 
s/\n\n7/3\n1\n/;t loop 
s/\n1\n8/9\n\n/;t loop 
s/\n\n8/4\n\n/;t loop 
s/\n1\n9/9\n1\n/;t loop 
s/\n\n9/4\n1\n/;t loop 
s/\n1\n/5\n\n/;t loop 
s/\n\n\(.\)/\1\n\n/;t loop 
s/\n\n$// 

Łącząc te, skrypt wykonać zadanie:

h 
s/, start.*// 
s/^/\n\n/ 
t loopa 
:loopa 
s/\n1\n0/5\n\n/;t loopa 
s/\n\n0/0\n\n/;t loopa 
s/\n1\n1/5\n1\n/;t loopa 
s/\n\n1/\n1\n/;t loopa 
s/\n1\n2/6\n\n/;t loopa 
s/\n\n2/1\n\n/;t loopa 
s/\n1\n3/6\n1\n/;t loopa 
s/\n\n3/2\n1\n/;t loopa 
s/\n1\n4/7\n\n/;t loopa 
s/\n\n4/2\n\n/;t loopa 
s/\n1\n5/7\n1\n/;t loopa 
s/\n\n5/2\n1\n/;t loopa 
s/\n1\n6/8\n\n/;t loopa 
s/\n\n6/3\n\n/;t loopa 
s/\n1\n7/8\n\n/;t loopa 
s/\n\n7/3\n1\n/;t loopa 
s/\n1\n8/9\n\n/;t loopa 
s/\n\n8/4\n\n/;t loopa 
s/\n1\n9/9\n1\n/;t loopa 
s/\n\n9/4\n1\n/;t loopa 
s/\n1\n/5\n\n/;t loopa 
s/\n\n\(.\)/\1\n\n/;t loopa 
s/\n\n$// 
H 
g 
s/.*, start/, start/ 
s/\n.*// 
s/$/\n\n/ 
t loopb 
:loopb 
s/0\n1\n/\n\n1/;t loopb 
s/0\n\n/\n\n0/;t loopb 
s/1\n1\n/\n\n3/;t loopb 
s/1\n\n/\n\n2/;t loopb 
s/2\n1\n/\n\n5/;t loopb 
s/2\n\n/\n\n4/;t loopb 
s/3\n1\n/\n\n7/;t loopb 
s/3\n\n/\n\n6/;t loopb 
s/4\n1\n/\n\n9/;t loopb 
s/4\n\n/\n\n8/;t loopb 
s/5\n1\n/\n1\n1/;t loopb 
s/5\n\n/\n1\n0/;t loopb 
s/6\n1\n/\n1\n3/;t loopb 
s/6\n\n/\n1\n2/;t loopb 
s/7\n1\n/\n1\n5/;t loopb 
s/7\n\n/\n1\n4/;t loopb 
s/8\n1\n/\n1\n7/;t loopb 
s/8\n\n/\n1\n6/;t loopb 
s/9\n1\n/\n1\n9/;t loopb 
s/9\n\n/\n1\n8/;t loopb 
s/\n1\n/\n\n1/;t loopb 
s/\(.\)\n\n/\n\n\1/;t loopb 
s/^\n\n// 
H 
g 
s/[^\n]*\n// 
s/\n// 

(Znacznie łatwiej w awk myśli.)

Uwaga: Kiedyś widziałem wdrożenie maszyny Turinga, więc staram się pamiętać, że wszystko, co można zrobić za pomocą języka programowania, można zrobić w sed. To oczywiście nie oznacza, że ​​sed jest dobrym narzędziem we wszystkich sytuacjach.

+0

Nie próbowałem tego zrozumieć, ale na podstawie Twojego komentarza wydaje się, że to się nie powiedzie dla niczego poza liczbami jednocyfrowymi. Nie można zastąpić tylko ostatniej liczby w izolacji. –

+0

Wiem, że nie mogę zastąpić tylko ostatniej liczby w izolacji. Właśnie dlatego mam 2 '\ n'. W przypadku mnożenia, prawo to jest rozwiązaniem, a w środku - cyfrą przenoszenia. – jfg956