Як я можу перевірити дослівні символи командного рядка bash?


15

Я мав цю дивну поведінку сьогодні вранці в терміналі "Баш":

user@home:/home/user$ [ -f /etc/openvpn/client.conf ] && echo true
bash: [: missing «]»
user@home:/home/user$ [ -f /etc/openvpn/client.conf ] && echo true
true
  • Перша команда була вставлена зі сценарію, відредагованого gedit.
  • Другий був набраний безпосередньо в терміналі.

Після деякого копання я виявляю , що видалення 30-го символу (пробіл між client.conf та "]") та заміна його на пробіл змусили команду знову працювати.

Моє припущення було правильним: невідомий порожній символ проскочив до команди , але питання:

  1. Як я можу виявити ці символи в терміналі, щоб я міг налагоджувати команду? І ще важливіше:
  2. Як я можу запобігти цьому повторитись?

До речі, я використовую Ubuntu 18.04 / французькою мовою, сценарій, з якого я вставляю команду, знаходиться на USB-накопичувачі і, можливо, редагувався і в Windows.


Дякую за дуже гарні відповіді. Поганий символ - символ UTF-8, що не порушує пробіл c2 a0 . Питання про те, як видалити спеціальний символ 'M-BM-' за допомогою sed, має цікавий факт.

Дивна річ у тому, що сценарій не містить цього персонажа. Тож я не знаю, звідки це взялося.


3
Використовуйте редактор, який виділяє такі символи. Виділення синтаксису також дуже допомагає. Ніколи не вставляйте безпосередньо з Інтернету в термінал, завжди проходьте вищезгаданий редактор.
чороба

2
Йо може захотіти знайти проблемну команду у вашому списку історії, а потім передати висновок через програму з шестигранним відображенням. Так що вам не потрібно перебирати довгий список, або повторіть команду, щоб розмістити її внизу списку історії, і запустіть history 2|xxd(адже сама historyкоманда завжди остання в списку), або введіть history|grep "CommandWithProblem"|xxd. Ви можете використовувати будь-яку іншу програму з шестигранним відображенням xxd, але це за замовчуванням у форматі, який мені подобається.
АФХ

@Gabriel Glenn, будь ласка, позначте найкращу / найкориснішу / будь-яку відповідь як " прийняту " за допомогою галочки, а не коментуючи кожен, що відповідь допомогла. info
Attie

1
@Attie, Так, я просто чекаю 24 години, перш ніж приймати найкращі відповіді, як це запропоновано в: meta.stackexchange.com/questions/5234/…
Габріель Гленн

1
Особисто я б користувався set -x. Це показало б вам команду та як вона розбита. Це не обов'язково буде говорити "поганий характер тут", але це показало б вам, що баш не розщеплюється на цього персонажа.
Патрік

Відповіді:


11

Один із варіантів - переглянути персонажів, які ви намагаєтеся використовувати разом із шестигранним переглядачем чи редактором. hexdump- хороший варіант, якщо ви обмежені терміналом.

$ hexdump -Cv <<"EOF"
> [ -f /etc/openvpn/client.conf ] && echo true
> EOF
00000000  5b 20 2d 66 20 2f 65 74  63 2f 6f 70 65 6e 76 70  |[ -f /etc/openvp|
00000010  6e 2f 63 6c 69 65 6e 74  2e 63 6f 6e 66 20 5d 20  |n/client.conf ] |
00000020  26 26 20 65 63 68 6f 20  74 72 75 65 0a           |&& echo true.|
0000002d

Ви можете побачити тут , що space, close-square-brace, spaceє правильними - 0x20, 0x5D, 0x20.

Ці значення - це коди ASCII, що відображаються у шістнадцятковій кількості . Будь-яке значення поза діапазону 0x20- 0x7Eне є " символом для друку " , що стосується ASCII, і, швидше за все, не буде добре грати з інтерфейсами командного рядка.

Примітка. Я скопіював ваш перший " зламаний " рядок для використання у hexdumpнаведеному вище прикладі, тож щось замінило простір not-an-ASCII на простір ASCII між вашим початковим джерелом та наданим запитанням.


Щоб повторити це, виконайте наступні дії:

  1. Введіть hexdump -Cv <<"EOF"і натиснітьEnter
  2. Вставте текст, який ви хочете використовувати
  3. Введіть EOFвласну лінію та натиснітьEnter

Термінали та інтерфейси командного рядка не справляються зі спеціальними символами - як ви виявили. Якщо ви не дуже обережні з форматуванням документів, у вас також будуть проблеми з Microsoft Word (та іншими) за допомогою " розумних цитат ", em-тире, список продовжується ...

Знайдіть різницю: (верх " розумні котирування ", нижній - " прямі котирування ")

Приклад розумних котирувань проти прямих цитат

$ hexdump -Cv <<"EOF"
> quoted string
> EOF
00000000  e2 80 9c 71 75 6f 74 65  64 20 73 74 72 69 6e 67  |...quoted string|
00000010  e2 80 9d 0a                                       |....|
00000014

Тут, відкриті лапки не просто ASCII лапки ( "), але є Unicode / UTF-8 серія - 0xE2, 0x80, 0x9Cабо U+201C- що термінал не обробляти як можна було б очікувати.

Пропозиція Ківі cat -Aтакож виконує цю роботу:

$ cat -A <<"EOF"
> quoted string
> EOF
M-bM-^@M-^\quoted stringM-bM-^@M-^]$

Примітка. Під час використанняecho "..." | hdви маєте шанс, що bash замінить частини рядка, які ви намагаєтеся перевірити. Це викликає особливе занепокоєння при спробі перевірити компоненти сценарію.

Наприклад, спробуйте:

$ echo "${USER}"
attie

$ echo "`whoami`"
attie

$ echo "$(whoami)"
attie

$ cat <<EOF
> ${USER}
> EOF
attie

Ці методи замінюють компоненти відповідним текстом. Щоб цього уникнути, скористайтеся одним із наступних підходів. Зверніть увагу на використання одиничних лапок ( ') і " котируваного гередока " ( "EOF").

$ echo '${USER}'
${USER}

$ echo '`whoami`'
`whoami`

$ echo '$(whoami)'
$(whoami)

$ cat <<"EOF"
> ${USER}
> EOF
${USER}

Це рішення працює: echo "[ -f /etc/openvpn.ovpn ]" | hd повертає [...] c2 a0 [...]. Ми можемо побачити c2 a0 UT-8 символи нерозривного пробілу
Габріель Гленн

18

Ви можете використовувати catз -Aопцією: з посібника:

   -A, --show-all
          equivalent to -vET
   -E, --show-ends
          display $ at end of each line
   -T, --show-tabs
          display TAB characters as ^I
   -v, --show-nonprinting
          use ^ and M- notation, except for LFD and TAB

Так cat -A yourscrip.shпокажуть вам невидимих ​​і дивних персонажів.


7
Це рішення працює: echo "[ -f /etc/openvpn.ovpn ]" | cat -Aповертає [ -f /etc/openvpn/client.ovpnM-BM- ]$. Ми можемо побачити M-BM- UT-8 символи нерозривного пробілу
Габріель Гленн

@GabrielGlenn рада, що це допомогло тобі.
Ківі

9

echo "<your command>" | hdповинні працювати. Шукайте зворотній простір (0x08) або символи з кодами> = 80. echo "<your command>" | wc -bі перевірка відповідності підрахунку тому, що ви бачите, також є хорошою ідеєю.

Копіювати матеріали з файлів, створених будь-яким іменем "Office", небезпечно, тому що таке програмне забезпечення часто вимагає сміливості замінювати символи: французькою мовою пильнуйте подвійні лапки, замінені на "guillemets", англійською мовою - звичайні цитати замінені на їх відкрити / закрити еквіваленти. Найскладнішим, який я коли-небудь знайшов, був нерозривний простір шириною 0 у середині імені файлу (3 дні простою сервера ...).


2
Варто згадати hdкороткий, про hexdumpякий також йдеться у відповіді Атті.
Mikael Kjær

@ MikaelKjær - У Ubuntu hdрівнозначний hexdump -C.
АФХ

1
@xenoid: я сказав "відредаговано в Windows", не відредагував програму Office Writer, ми не божевільні;). Якщо його редагували, це було з Notepad ++.
Габріель Гленн

1
Це рішення працює: echo "[ -f /etc/openvpn.ovpn ]" | hd повертає [...] c2 a0 [...]. Ми можемо побачити c2 a0 UT-8 символи нерозривного пробілу
Габріель Гленн

2

Bash та інші оболонки, такі як zsh, можуть відкрити поточний командний рядок у редакторі. За замовчуванням ярлика для Баша C-x C-e( CtrlX CtrlE), і вона відкривається в першому доступні $VISUAL, $EDITORі Emacs. На практиці це безцінно для налагодження та зміни складних команд. Залежно від того, як ви дивитесь на це, zsh є більш привітним, ніж bash тут: коли редактор виходить, bash запускає команду негайно, тоді як zsh чекає, коли ви натиснете Enter(даючи більше шансів редагувати команду).

Після відкриття команди в редакторі ви можете налаштувати свої редактори так, щоб вони не відрізнялися від ASCII.

Наприклад, з Vim , використовуючи ці налаштування:

set encoding=latin1
set isprint=
set display+=uhex

введіть тут опис зображення

Або, адаптуючи методи інших відповідей:

bash-4.4$ f() { cat -A "$@"; false; }   # exit false to prevent bash from running the command
bash-4.4$ VISUAL=f
bash-4.4$ [ -f /etc/openvpn/client.conf ] && echo true  # C-x C-e here
[ -f /etc/openvpn/client.confM-BM- ] && echo true$
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.