Drukując znak dziesiętny na znak ascii, moje polecenie nie wyświetla danych zgodnie z przeznaczeniem

14

Chciałem wypisać ciąg wszystkich znaków ascii za pomocą następującego polecenia

for i in `seq 32 127`; do printf "%c" $i; done

Dane wyjściowe powyższego polecenia to:

33333334444444444555555555566666666667777777777..............

Jest to pierwsza (od lewej) cyfra każdego numeru.

Przeglądając tę ​​stronę natknąłem się na odpowiedź na mój problem. Jak wydrukować wszystkie drukowalne znaki ASCII w CLI? , ale nadal nie rozumiem, dlaczego mój oryginalny fragment nie wyświetla znaków ascii zgodnie z przeznaczeniem.

Ifthikhan
źródło
1
POSIX narzuca to, oto comp.unix.shellwątek, dlaczego to jest słuszne;)
sr_
@ sr_ Dziękujemy za wskazanie wątku. Miał wyjaśnienie, którego szukałem.
Ifthikhan,

Odpowiedzi:

13

Nie można bezpośrednio wydrukować kodów ascii, używając printf "%c" $ipodobnego w C.

Musisz najpierw przekonwertować wartość dziesiętną i na wartość ósemkową, a następnie wydrukować ją, używając printfi wstawiając \odpowiednie wartości ósemkowe.

Aby wydrukować A, musisz przekonwertować liczbę dziesiętną 65 na liczbę ósemkową, tj. 101, a następnie wydrukować tę liczbę ósemkową jako:

printf "\101\n"

To zostanie wydrukowane A.

Musisz go zmodyfikować, aby:

for i in `seq 32 127`; do printf \\$(printf "%o" $i);done;

Ale używając awkmożesz drukować bezpośrednio jak w języku C.

awk 'BEGIN{for(i=32;i<=127;i++)printf "%c",i}';echo
pradeepchhetri
źródło
7
W bashi zshmożna to zrobić bez pętli i bez zewnętrznego polecenia: printf $(printf '\%o' {32..127}).
manatwork
@manatwork: Dokładnie… bardzo dziękuję za wskazanie tego…
pradeepchhetri,
1
@pradeepchhetri: Dziękuję za szczegółową odpowiedź, która zdawała się obejmować większość wymaganych szczegółów (stąd wybieram odpowiedź). Jednak myślę, że ominęło ważną informację, która może znajdować się w następującym komunikatem na unix.derkeiler.com/Newsgroups/comp.unix.shell/2007-07/... . Stwierdza się, że „Argumenty argumentów należy traktować jak łańcuchy, jeśli odpowiednim specyfikatorem konwersji jest b, c lub s ...”
Ifthikhan
To nie jest (char)(127)backspace ani coś takiego. Cokolwiek to jest, pojawia się jako jedno z pól hex lub jakkolwiek się je nazywa. Jeśli chcesz tylko „do wydrukowania” (tj. Do odczytu), po prostu przejdź do 126. Również miła myśl z ósemką. To sprytne; Myślałem w kategoriach szesnastkowych (jak printf '\x%x; {32..126}... lub 127, jak sądzę, skoro wszyscy to zrobiliście), ale to nie działa. Octal ratuje dzień! :) Wreszcie, @Iththikhan, nie jestem pewien, co masz na myśli. awkczęsto używa poleceń w stylu C i nigdzie indziej nie jest %cużywany. Używanie liczb ósemkowych różni się od używania znaków jednobajtowych.
Dylan,
3

%c Interpretuje powiązany argument jako char: wypisywany jest tylko pierwszy znak danego argumentu

Wydaje się, że masz już sposób na ich wydrukowanie, ale tutaj jest jeden wariant.

for i in `seq 32 127`; do printf "\x$(printf "%x" $i) $i"; done
Peter.O
źródło
0

Potrzebujesz printf, ale tylko raz; możesz zastąpić jedno użycie printfprostszym i bardziej wydajnymecho sekwencjami ucieczki Bash:

Z hexagesimals:

for i in `seq 32 127`; do
  echo -ne \\x$(printf %02x $i)
done

Z ósemkami:

for i in `seq 32 127`; do
  echo -ne \\0$(printf %03o $i)
done
Luchostein
źródło