Dlaczego polecenia „echo -e” wydają się nie generować właściwych wyników?

21

W terminalu Ubuntu 18.04 LTS, kiedy piszę to polecenie:

echo -e "Hello\\\n"

Daje to jako wynik:

Hello\n

Ale to powinno wydrukować, ponieważ mężczyzna strona mówi:

Hello\

Oznacza to, że najpierw wydrukuj Hello, a \następnie znak nowej linii (a następnie kolejną nową linię). Gdzie jest problem?

Zobacz te kilka echo -epoleceń i ich wyniki :

man420@man420-X542UQ:~$ echo -e "HEllo\a\a\a\a\a\a\\\n"
HEllo\n
man420@man420-X542UQ:~$ echo -e "HEllo\\\n"
HEllo\n
man420@man420-X542UQ:~$ echo -e "HEllo\a\\\n"
HEllo\n
yolin00
źródło
tak. dla pierwszych 2 \ powinien wypisać \ .i ostatni \ an n zrobić ukośnik odwrotny \ n (nowa linia). więc dlaczego powinien wypisać Hello \
yolin00
1
Wypróbuj bez cytatów.
ajgringo619
2
Zadziwiającą odpowiedź udzielił Eliah Kagan, którą powinieneś zaakceptować.
wanad
2
Nie używaj echoprzede wszystkim: używaj printf.
chepner
2
Zawsze używaj pojedynczych cudzysłowów, jeśli chcesz mieć pewność, że to, co piszesz, jest dokładnie tym, co przekazywane do polecenia jako argument.
Giacomo Alzetta

Odpowiedzi:

29

Odwrotne ukośniki są traktowane specjalnie przez echo -e, ale najpierw są one traktowane specjalnie przez powłokę (która w tym przypadku jest bash), zgodnie z regułami cytowania powłoki .

Argument echofaktycznie widzi to Hello\\n. Ponieważ minęło -esię echo, traktuje Odwrotny ukośnik cytuje specjalnie, i \\jest zwinięta do pojedynczej \. Finał nnie jest ucieczkowy, więc wydaje się dosłownie.

Powodem tego jest to, że przed i niezależnie od samego działania echo, powłoka traktuje \specjalnie w niektórych kontekstach, ale nie w innych. Nienotowane \znaki są zawsze traktowane specjalnie, jedno-cytowany \ nigdy nie są traktowane specjalnie, ale leczenie podwójnie cytowany \ znaków, jak w poleceniu uruchomiono, jest bardziej subtelne i skomplikowane.

Gdy powłoka napotyka tekst w cudzysłowie, podobnie jak w przypadku polecenia, "Hello\\\n"traktuje go \jako znak zmiany znaczenia, gdy poprzedza znak, który może mieć specjalne znaczenie w cudzysłowach, a nie inaczej .

  1. Ponieważ \czasami ma w środku specjalne znaczenie "", to, \co bezpośrednio poprzedza inne \, powoduje zacytowanie tej sekundy \. Wewnątrz podwójnych cudzysłowów pierwsze \\są zwinięte \.
  2. Po tych dwóch pierwszych \znakach pojawia się trzeci \znak, na który nie wpływają pierwsze dwa znaki i który poprzedza znak an n. Ale nnie jest postacią, która jest traktowana specjalnie wewnątrz podwójnych cudzysłowów, więc \wcześniej nie jest traktowana specjalnie w tej sytuacji. Tak \nzostaje \n.

Skutkuje to tym, że w podwójnych cudzysłowach \\\njest interpretowany jako \\n.

Kiedy echo -ewidzi \\n, pierwszy \usuwa specjalne znaczenie z drugiego, więc echodrukuje \ndosłownie dla tego tekstu.


Jeśli Twoim celem jest wydrukowanie Helloz nowym znakiem nowej linii, ale bez ukośników odwrotnych (pytanie było pierwotnie dwuznaczne, a myślę, że jest to przydatny przykład), wówczas jednym z rozwiązań jest usunięcie znaku\ . Uruchamianie echo -e "Hello\\n"wyników Helloz dodatkową nową linią na końcu.

Lepszym rozwiązaniem jest stosowanie pojedynczych cudzysłowów i pisanie echo -e 'Hello\n'. Pojedyncze cytaty to najsilniejsza forma cytowania. Jeszcze lepszym rozwiązaniem jest użycie printfzamiast tego echo, co w tym przypadku byłoby printf 'Hello\n\n'.

Jeśli Twoim celem jest wydrukowanie z Hello\uwzględnieniem odwrotnego ukośnika, a następnie dodatkowego nowego wiersza , możliwe jest zastosowanie podwójnego cytowania, ale uciążliwe. Aby to zrozumieć, pracuj wstecz: echo -ekonwertuje \\na \i \ndo nowej linii, a podwójne cudzysłowy konwertuje \\na \, abyś mógł to zrobić za pomocą sześciu ukośników odwrotnych ( echo -e "Hello\\\\\\n"), ponieważ \\nzmienia się w \nskutek ucieczki jednego ukośnika odwrotnego. Możesz to również zrobić z pięcioma, ponieważ podwójne cytowanie zachowuje się, \ngdy \nie jest poprzedzane znakiem ucieczki.

To ilustruje korzyść echo -epojedynczego cudzysłowu : po prostu umieść wszystko, co chcesz zobaczyć w pojedynczym cudzysłowie ( echo -e 'Hello\\\n'). printftutaj też jest dobrze. Jedną z opcji jest printf 'Hello\\\n\n'. Ale printfnaprawdę wyróżnia się to, że możesz podłączyć dodatkowe argumenty. Możesz użyć printf '%s\n\n' 'Hello\', który wstawia drugi argument (dosłownie, Hello\ponieważ pojedyncze cudzysłowy niczego nie zmieniają) zamiast %s.

Eliah Kagan
źródło