2012-02-03 14 views
10

Pracuję nad skryptem powłoki, który będzie używany przez innych i może przyjmować podejrzane ciągi. Opiera się on na awk, więc jako podstawowa miara odporności, chcę mieć awk wyprowadzane łańcuchy zakończone nullem - komendy, które będą otrzymywały dane z awk, mogą w ten sposób uniknąć pewnej ilości zerwania ze stringów, które zawierają spacje lub nie-często -in-angielskie znaki.Jak mogę wyprowadzać łańcuchy zakończone znakiem NUL w Awk?

Niestety, z podstawowej dokumentacji awk, nie wiem, jak powiedzieć awk, aby wydrukować ciąg zakończony znakiem ASCII, a nie znakiem nowej linii. Jak mogę powiedzieć awk, że chcę ciągi zakończone znakiem NUL?


wersje awk, które mogą być stosowane:

[[email protected]]$ awk --version 
awk version 20070501 

[[email protected]]$ awk -W version 
mawk 1.3.3 Nov 1996, Copyright (C) Michael D. Brennan 

[[email protected]]$ awk -W version 
GNU Awk 3.1.7 

więc prawie cała rodzina awk wersjach. Jeśli będziemy musieli skonsolidować wersję, prawdopodobnie będzie to GNU Awk, ale odpowiedzi na wszystkie wersje są mile widziane, ponieważ być może będę musiał działać we wszystkich tych awariach. Och, starsze skrypty.

+0

najlepszym przewodnikiem znalazłem do tej pory: http://sandrotosi.blogspot.com/2011/09/print-nul-terminated-string-with-awk.html - ale To nie jest pełna odpowiedź, a także przypadkowy blog blogspot ma mniej SEO niż SO, więc dobra odpowiedź na WR będzie przydatna dla większej liczby osób. –

+2

Wypróbuj 'awk -F $ '\ 0'' – Kevin

+0

Kevin: Czy chcesz zrobić z tego odpowiedź? –

Odpowiedz

15

Dobra, mam to.

awk '{printf "%s\0", $0}' 

Lub przy ORS,

awk -vORS=$'\0' // 
+1

Kiedy przesyłam wyniki tych inkantacji do 'xargs -0', nie rozdziela się na' \ 0', który wstawia awk (testowany przez dzielenie na coś innego). :( –

+0

@SeanM Pierwszy wydaje się nie działać, ale drugi działa dla mnie, czy jesteś pewien, że problem jest w 'awk'? (Spróbuj zapisać wyjście z właśnie tego do pliku) – Kevin

+0

To nie zadziałało na wszystkich trzech platformach, ale doprowadziło mnie to do stwierdzenia, że ​​mógłbym zrobić to, co chciałem z Perlem - co zawsze zdarza się, gdy chcę zrobić coś, co jest skomplikowane z awk lub sed. Ponieważ twoja odpowiedź zadziałała przynajmniej w części czas i postaw mnie na drodze do rozwiązania, akceptuję to. :) –

-1

mam rozwiązany drukowania ASCII 0 z awk. używam UNIX polecenia printf "\ 000"

echo | awk -v s='printf "\000"' '{system(s);}' 
+0

'sh: 1: Błąd składni: niezakończony cytowany ciąg' –

9

Istnieją trzy alternatywy:

  1. Ustawianie ORS do ASCII zera: Inne rozwiązania mają awk -vORS=$'\0' ale:
    $'\0' jest konstruktem specyficzne niektóre powłoki (bash, zsh).
    A więc: to polecenie awk -vORS=$'\0' nie będzie działać w większości starszych powłok.

Istnieje opcja zapisania go jako: awk 'BEGIN { ORS = "\0" } ; { print $0 }', ale to nie zadziała w przypadku większości wersji awk.

  1. Drukowanie (printf) z charakterem \0: awk '{printf("%s\0", $0)}'

  2. Drukowanie bezpośrednio ASCII 0: awk '{ printf("%s%c", $0, 0)}'

Testowanie wszystkie alternatywy z tym kodem:

#!/bin/bash 

test1(){ # '{printf("%s%c",$0,0)}'| 
    a='awk,mawk,original-awk,busybox awk' 
    IFS=',' read -ra line <<<"$a" 
    for i in "${line[@]}"; do 
     printf "%14.12s %40s" "$i" "$1" 
     echo -ne "a\nb\nc\n" | 
     $i "$1"| 
     od -cAn; 
    done 
} 

#test1 '{print}' 
test1 'BEGIN { ORS = "\0" } ; { print $0 }' 
test1 '{ printf "%s\0", $0}' 
test1 '{ printf("%s%c", $0, 0)}' 

Otrzymujemy następujące wyniki:

  awk  BEGIN { ORS = "\0" } ; { print $0 } a \0 b \0 c \0 
      mawk  BEGIN { ORS = "\0" } ; { print $0 } a b c 
    original-awk  BEGIN { ORS = "\0" } ; { print $0 } a b c 
    busybox awk  BEGIN { ORS = "\0" } ; { print $0 } a b c 
      awk      { printf "%s\0", $0} a \0 b \0 c \0 
      mawk      { printf "%s\0", $0} a b c 
    original-awk      { printf "%s\0", $0} a b c 
    busybox awk      { printf "%s\0", $0} a b c 
      awk    { printf("%s%c", $0, 0)} a \0 b \0 c \0 
      mawk    { printf("%s%c", $0, 0)} a \0 b \0 c \0 
    original-awk    { printf("%s%c", $0, 0)} a \0 b \0 c \0 
    busybox awk    { printf("%s%c", $0, 0)} a b c 

Jak widać powyżej, pierwsze dwa rozwiązania działają tylko w GNU AWK.

Najbardziej przenośne to trzecie rozwiązanie: '{ printf("%s%c", $0, 0)}'.

Żadne rozwiązanie nie działa poprawnie w "awoku zajęciowym awk".

Wersje wykorzystywane do tego badania były:

  awk> GNU Awk 4.0.1 
     mawk> mawk 1.3.3 Nov 1996, Copyright (C) Michael D. Brennan 
original-awk> awk version 20110810 
     busybox> BusyBox v1.20.2 (Debian 1:1.20.0-7) multi-call binary. 
+0

Wiele błogosławieństw na ciebie za określenie wersji, których użyłeś! Problem, który zainspirował to pytanie, już dawno stał się "Nie mój", ale dobrze mi jest widzieć ludzi, którzy opuszczają pomocne, pilne odpowiedzi. Dobra robota. –

1

Można również rura swój awk „s Wyjście przez tr:

awk '{...code...}' infile | tr '\n' '\0' > outfile 

Wystarczy badanego, to działa przynajmniej na Linux i FreeBSD.

Jeśli nie możesz użyć znaków nowej linii jako separatorów (na przykład, jeśli rekordy wyjściowe mogą zawierać znaki nowej linii w środku), użyj po prostu innej litery, która z pewnością nie pojawi się w rekordzie, np. jeden z kodem 1:

awk 'BEGIN { ORS="\001" } {...code...}' | tr '\001' '\0' 
Powiązane problemy