Используя «while read ...», echo и printf получают разные результаты

Начиная с Lubuntu 14.04 или ранее, формат файла конфигурации и ответ теперь немного отличаются от ответа @ SWrobel. В Ubuntu 17.10 или ранее он стал другим. Следующие инструкции были обновлены до Ubuntu 17.10:

Удалите следующие строки из ~/.config/openbox/lubuntu-rc.xml, чтобы отключить переключение рабочего стола колесика прокрутки в окне, с помощью и без клавиш-модификаторов. (Тем не менее, удерживайте внешний элемент <context …> … </context>.) [F1] Также удалите следующие строки, чтобы отключить отображение рабочего стола на колесиках прокрутки на фоне рабочего стола:
<context name="Desktop">
  <mousebind button="A-Up" action="Click">
    <action name="GoToDesktop">
      <to>previous</to>
    </action>
  </mousebind>
  <mousebind button="A-Down" action="Click">
    <action name="GoToDesktop">
      <to>next</to>
    </action>
  </mousebind>
  <mousebind button="C-A-Up" action="Click">
    <action name="GoToDesktop">
      <to>previous</to>
    </action>
  </mousebind>
  <mousebind button="C-A-Down" action="Click">
    <action name="GoToDesktop">
      <to>next</to>
    </action>
  </mousebind>
  <mousebind button="Left" action="Press">
    <action name="Focus"/>
    <action name="Raise"/>
  </mousebind>
  <mousebind button="Right" action="Press">
    <action name="Focus"/>
    <action name="Raise"/>
  </mousebind>
</context>
Также удалите следующие строки, чтобы отключить любое перемещение рабочего стола колесика прокрутки при перемещении окна вокруг:
<context name="MoveResize">
  <mousebind button="Up" action="Click">
    <action name="GoToDesktop">
      <to>previous</to>
    </action>
  </mousebind>
  <mousebind button="Down" action="Click">
    <action name="GoToDesktop">
      <to>next</to>
    </action>
  </mousebind>
  <mousebind button="A-Up" action="Click">
    <action name="GoToDesktop">
      <to>previous</to>
    </action>
  </mousebind>
  <mousebind button="A-Down" action="Click">
    <action name="GoToDesktop">
      <to>next</to>
    </action>
  </mousebind>
</context>
Выполните это, чтобы настройки сразу же вступили в силу [источник]:
openbox --reconfigure
14
задан 22 July 2017 в 12:08

6 ответов

Это не просто эхо vs printf

Сначала давайте поймем, что происходит с частью read a b c. read выполнит разбиение слов на основе значения по умолчанию для переменной IFS, которая является пробелом-табу-новой линией, и поместит все на основе этого. Если есть больше входных данных, чем переменные, чтобы удерживать его, он будет разделять разделенные части на первые переменные, а то, что не может быть установлено, - уйдет в прошлое. Вот что я имею в виду:

bash-4.3$ read a b c <<< "one two three four"
bash-4.3$ echo $a
one
bash-4.3$ echo $b
two
bash-4.3$ echo $c
three four

Именно так описано в руководстве bash (см. Цитату в конце ответа).

В вашем Случай, который случается, состоит в том, что 1 и 2 вписываются в переменные a и b, а c принимает все остальное, что является 3 4 5 6.

То, что вы также увидите много раз, это то, что люди используют while IFS= read -r line; do ... ; done < input.txt для чтения текстовых файлов по строкам. Опять же, IFS= здесь по какой-то причине управляет расщеплением слов, а точнее - отключает его и считывает одну строку текста в переменную. Если его там не было, read будет пытаться подгонять каждое отдельное слово к переменной line. Но это еще одна история, которую я рекомендую вам изучить позже, поскольку while IFS= read -r variable - очень часто используемая структура.

echo vs printf behavior

echo делает то, что вы ожидайте здесь. Он отображает ваши переменные точно так же, как read разместил их. Это уже было продемонстрировано в предыдущем обсуждении.

printf очень особенный, потому что он будет продолжать подгонять переменные в строку формата до тех пор, пока все они не будут исчерпаны. Поэтому, когда вы делаете printf "%d, %d, %d \n" $a $b $c, printf видит строку формата с тремя десятичными знаками, но есть больше аргументов, чем 3 (потому что ваши переменные фактически расширяются до отдельных 1,2,3,4,5,6). Это может показаться запутанным, но существует по какой-то причине как улучшенное поведение от того, что делает настоящая функция printf() на языке C.

То, что вы также сделали здесь, что влияет на результат, заключается в том, что ваши переменные не цитируются, который позволяет оболочке (а не printf) разбивать переменные на 6 отдельных элементов. Сравните это с цитированием:

bash-4.3$ read a b c <<< "1 2 3 4"
bash-4.3$ printf "%d %d %d\n" "$a" "$b" "$c"
bash: printf: 3 4: invalid number
1 2 3

Точно, потому что переменная $c цитируется, теперь она распознается как целая строка, 3 4, и она не соответствует формату %d, который это только одно целое

Теперь сделайте то же самое без кавычек:

bash-4.3$ printf "%d %d %d\n" $a $b $c
1 2 3
4 0 0

printf снова говорит: «Хорошо, у вас есть 6 элементов, но формат показывает только 3, поэтому Я буду продолжать подгонять вещи и оставлять пустым все, что не могу соответствовать фактическому вводу от пользователя ».

И во всех этих случаях вам не нужно об этом говорить. Просто запустите strace -e trace=execve и убедитесь, что команда действительно «видит»:

bash-4.3$ strace -e trace=execve printf "%d %d %d\n" $a $b $c
execve("/usr/bin/printf", ["printf", "%d %d %d\\n", "1", "2", "3", "4"], [/* 80 vars */]) = 0
1 2 3
4 0 0
+++ exited with 0 +++

bash-4.3$ strace -e trace=execve printf "%d %d %d\n" "$a" "$b" "$c"
execve("/usr/bin/printf", ["printf", "%d %d %d\\n", "1", "2", "3 4"], [/* 80 vars */]) = 0
1 2 printf: ‘3 4’: value not completely converted
3
+++ exited with 1 +++

Дополнительные примечания

Как правильно заметил Чарльз Даффи в комментариях, bash имеет свой собственный встроенный printf, который вы используете в своей команде, strace на самом деле вызовет версию /usr/bin/printf, а не версию оболочки. Помимо незначительных различий, для нашего интереса к этому конкретному вопросу, спецификаторы стандартного формата одинаковы, а поведение одинаковое.

Что также следует иметь в виду, так это то, что синтаксис printf гораздо более переносимый ( и поэтому предпочтительнее), чем echo, не говоря уже о том, что синтаксис более знаком с C или любым C-подобным языком, который имеет функцию printf() в нем. См. Этот отличный ответ terdon по теме printf vs echo. Хотя вы можете сделать вывод, адаптированный к вашей конкретной оболочке, в вашей конкретной версии Ubuntu, если вы собираетесь переносить скрипты в разные системы, вам, скорее всего, следует предпочесть printf, а не эхо. Возможно, вы начинающий системный администратор, работающий с машинами Ubuntu и CentOS, или, может быть, даже с FreeBSD - кто знает - поэтому в таких случаях вам придется делать выбор.

Цитата из руководства bash, SHELL BUILTIN COMMANDS раздел

читать [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [- N nchars] [-p prompt] [-t timeout] [-u fd] [name ...] Одна строка считывается со стандартного ввода или из файлового дескриптора fd, предоставленного в качестве аргумента опции -u, и первое слово присваивается первому имени, второму слову второму имени и т. д., с остальными словами и их промежуточными разделителями, назначенными на фамилию. Если из входного потока меньше слов, чем имен, оставшимся именам присваиваются пустые значения. Символы IFS используются для разделения строки на слова, используя те же правила, которые использует оболочка для расширения (описанная выше в разделе «Разделение слов»).
24
ответ дан 22 May 2018 в 20:18
  • 1
    Одно примечательное различие между случаем strace и другим - strace printf использует /usr/bin/printf, тогда как printf непосредственно в bash использует оболочку, встроенную с тем же именем. Они не всегда будут идентичными - например, экземпляр bash имеет спецификаторы формата %q и в новых версиях $()T для форматирования времени. – Charles Duffy 22 July 2017 в 18:46

Это не просто эхо vs printf

Сначала давайте поймем, что происходит с частью read a b c. read выполнит разбиение слов на основе значения по умолчанию для переменной IFS, которая является пробелом-табу-новой линией, и поместит все на основе этого. Если есть больше входных данных, чем переменные, чтобы удерживать его, он будет разделять разделенные части на первые переменные, а то, что не может быть установлено, - уйдет в прошлое. Вот что я имею в виду:

bash-4.3$ read a b c <<< "one two three four" bash-4.3$ echo $a one bash-4.3$ echo $b two bash-4.3$ echo $c three four

Именно так описано в руководстве bash (см. Цитату в конце ответа).

В вашем Случай, который случается, состоит в том, что 1 и 2 вписываются в переменные a и b, а c принимает все остальное, что является 3 4 5 6.

То, что вы также увидите много раз, это то, что люди используют while IFS= read -r line; do ... ; done < input.txt для чтения текстовых файлов по строкам. Опять же, IFS= здесь по какой-то причине управляет расщеплением слов, а точнее - отключает его и считывает одну строку текста в переменную. Если его там не было, read будет пытаться подгонять каждое отдельное слово к переменной line. Но это еще одна история, которую я рекомендую вам изучить позже, поскольку while IFS= read -r variable - очень часто используемая структура.

echo vs printf behavior

echo делает то, что вы ожидайте здесь. Он отображает ваши переменные точно так же, как read разместил их. Это уже было продемонстрировано в предыдущем обсуждении.

printf очень особенный, потому что он будет продолжать подгонять переменные в строку формата до тех пор, пока все они не будут исчерпаны. Поэтому, когда вы делаете printf "%d, %d, %d \n" $a $b $c, printf видит строку формата с тремя десятичными знаками, но есть больше аргументов, чем 3 (потому что ваши переменные фактически расширяются до отдельных 1,2,3,4,5,6). Это может показаться запутанным, но существует по какой-то причине как улучшенное поведение от того, что делает настоящая функция printf() на языке C.

То, что вы также сделали здесь, что влияет на результат, заключается в том, что ваши переменные не цитируются, который позволяет оболочке (а не printf) разбивать переменные на 6 отдельных элементов. Сравните это с цитированием:

bash-4.3$ read a b c <<< "1 2 3 4" bash-4.3$ printf "%d %d %d\n" "$a" "$b" "$c" bash: printf: 3 4: invalid number 1 2 3

Точно, потому что переменная $c цитируется, теперь она распознается как целая строка, 3 4, и она не соответствует формату %d, который это только одно целое

Теперь сделайте то же самое без кавычек:

bash-4.3$ printf "%d %d %d\n" $a $b $c 1 2 3 4 0 0

printf снова говорит: «Хорошо, у вас есть 6 элементов, но формат показывает только 3, поэтому Я буду продолжать подгонять вещи и оставлять пустым все, что не могу соответствовать фактическому вводу от пользователя ».

И во всех этих случаях вам не нужно об этом говорить. Просто запустите strace -e trace=execve и убедитесь, что команда действительно «видит»:

bash-4.3$ strace -e trace=execve printf "%d %d %d\n" $a $b $c execve("/usr/bin/printf", ["printf", "%d %d %d\\n", "1", "2", "3", "4"], [/* 80 vars */]) = 0 1 2 3 4 0 0 +++ exited with 0 +++ bash-4.3$ strace -e trace=execve printf "%d %d %d\n" "$a" "$b" "$c" execve("/usr/bin/printf", ["printf", "%d %d %d\\n", "1", "2", "3 4"], [/* 80 vars */]) = 0 1 2 printf: ‘3 4’: value not completely converted 3 +++ exited with 1 +++

Дополнительные примечания

Как правильно заметил Чарльз Даффи в комментариях, bash имеет свой собственный встроенный printf, который вы используете в своей команде, strace на самом деле вызовет версию /usr/bin/printf, а не версию оболочки. Помимо незначительных различий, для нашего интереса к этому конкретному вопросу, спецификаторы стандартного формата одинаковы, а поведение одинаковое.

Что также следует иметь в виду, так это то, что синтаксис printf гораздо более переносимый ( и поэтому предпочтительнее), чем echo, не говоря уже о том, что синтаксис более знаком с C или любым C-подобным языком, который имеет функцию printf() в нем. См. Этот отличный ответ terdon по теме printf vs echo. Хотя вы можете сделать вывод, адаптированный к вашей конкретной оболочке, в вашей конкретной версии Ubuntu, если вы собираетесь переносить скрипты в разные системы, вам, скорее всего, следует предпочесть printf, а не эхо. Возможно, вы начинающий системный администратор, работающий с машинами Ubuntu и CentOS, или, может быть, даже с FreeBSD - кто знает - поэтому в таких случаях вам придется делать выбор.

Цитата из руководства bash, SHELL BUILTIN COMMANDS раздел

читать [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [- N nchars] [-p prompt] [-t timeout] [-u fd] [name ...] Одна строка считывается со стандартного ввода или из файлового дескриптора fd, предоставленного в качестве аргумента опции -u, и первое слово присваивается первому имени, второму слову второму имени и т. д., с остальными словами и их промежуточными разделителями, назначенными на фамилию. Если из входного потока меньше слов, чем имен, оставшимся именам присваиваются пустые значения. Символы IFS используются для разделения строки на слова, используя те же правила, которые использует оболочка для расширения (описанная выше в разделе «Разделение слов»).
24
ответ дан 18 July 2018 в 09:53

Это не просто эхо vs printf

Сначала давайте поймем, что происходит с частью read a b c. read выполнит разбиение слов на основе значения по умолчанию для переменной IFS, которая является пробелом-табу-новой линией, и поместит все на основе этого. Если есть больше входных данных, чем переменные, чтобы удерживать его, он будет разделять разделенные части на первые переменные, а то, что не может быть установлено, - уйдет в прошлое. Вот что я имею в виду:

bash-4.3$ read a b c <<< "one two three four" bash-4.3$ echo $a one bash-4.3$ echo $b two bash-4.3$ echo $c three four

Именно так описано в руководстве bash (см. Цитату в конце ответа).

В вашем Случай, который случается, состоит в том, что 1 и 2 вписываются в переменные a и b, а c принимает все остальное, что является 3 4 5 6.

То, что вы также увидите много раз, это то, что люди используют while IFS= read -r line; do ... ; done < input.txt для чтения текстовых файлов по строкам. Опять же, IFS= здесь по какой-то причине управляет расщеплением слов, а точнее - отключает его и считывает одну строку текста в переменную. Если его там не было, read будет пытаться подгонять каждое отдельное слово к переменной line. Но это еще одна история, которую я рекомендую вам изучить позже, поскольку while IFS= read -r variable - очень часто используемая структура.

echo vs printf behavior

echo делает то, что вы ожидайте здесь. Он отображает ваши переменные точно так же, как read разместил их. Это уже было продемонстрировано в предыдущем обсуждении.

printf очень особенный, потому что он будет продолжать подгонять переменные в строку формата до тех пор, пока все они не будут исчерпаны. Поэтому, когда вы делаете printf "%d, %d, %d \n" $a $b $c, printf видит строку формата с тремя десятичными знаками, но есть больше аргументов, чем 3 (потому что ваши переменные фактически расширяются до отдельных 1,2,3,4,5,6). Это может показаться запутанным, но существует по какой-то причине как улучшенное поведение от того, что делает настоящая функция printf() на языке C.

То, что вы также сделали здесь, что влияет на результат, заключается в том, что ваши переменные не цитируются, который позволяет оболочке (а не printf) разбивать переменные на 6 отдельных элементов. Сравните это с цитированием:

bash-4.3$ read a b c <<< "1 2 3 4" bash-4.3$ printf "%d %d %d\n" "$a" "$b" "$c" bash: printf: 3 4: invalid number 1 2 3

Точно, потому что переменная $c цитируется, теперь она распознается как целая строка, 3 4, и она не соответствует формату %d, который это только одно целое

Теперь сделайте то же самое без кавычек:

bash-4.3$ printf "%d %d %d\n" $a $b $c 1 2 3 4 0 0

printf снова говорит: «Хорошо, у вас есть 6 элементов, но формат показывает только 3, поэтому Я буду продолжать подгонять вещи и оставлять пустым все, что не могу соответствовать фактическому вводу от пользователя ».

И во всех этих случаях вам не нужно об этом говорить. Просто запустите strace -e trace=execve и убедитесь, что команда действительно «видит»:

bash-4.3$ strace -e trace=execve printf "%d %d %d\n" $a $b $c execve("/usr/bin/printf", ["printf", "%d %d %d\\n", "1", "2", "3", "4"], [/* 80 vars */]) = 0 1 2 3 4 0 0 +++ exited with 0 +++ bash-4.3$ strace -e trace=execve printf "%d %d %d\n" "$a" "$b" "$c" execve("/usr/bin/printf", ["printf", "%d %d %d\\n", "1", "2", "3 4"], [/* 80 vars */]) = 0 1 2 printf: ‘3 4’: value not completely converted 3 +++ exited with 1 +++

Дополнительные примечания

Как правильно заметил Чарльз Даффи в комментариях, bash имеет свой собственный встроенный printf, который вы используете в своей команде, strace на самом деле вызовет версию /usr/bin/printf, а не версию оболочки. Помимо незначительных различий, для нашего интереса к этому конкретному вопросу, спецификаторы стандартного формата одинаковы, а поведение одинаковое.

Что также следует иметь в виду, так это то, что синтаксис printf гораздо более переносимый ( и поэтому предпочтительнее), чем echo, не говоря уже о том, что синтаксис более знаком с C или любым C-подобным языком, который имеет функцию printf() в нем. См. Этот отличный ответ terdon по теме printf vs echo. Хотя вы можете сделать вывод, адаптированный к вашей конкретной оболочке, в вашей конкретной версии Ubuntu, если вы собираетесь переносить скрипты в разные системы, вам, скорее всего, следует предпочесть printf, а не эхо. Возможно, вы начинающий системный администратор, работающий с машинами Ubuntu и CentOS, или, может быть, даже с FreeBSD - кто знает - поэтому в таких случаях вам придется делать выбор.

Цитата из руководства bash, SHELL BUILTIN COMMANDS раздел

читать [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [- N nchars] [-p prompt] [-t timeout] [-u fd] [name ...] Одна строка считывается со стандартного ввода или из файлового дескриптора fd, предоставленного в качестве аргумента опции -u, и первое слово присваивается первому имени, второму слову второму имени и т. д., с остальными словами и их промежуточными разделителями, назначенными на фамилию. Если из входного потока меньше слов, чем имен, оставшимся именам присваиваются пустые значения. Символы IFS используются для разделения строки на слова, используя те же правила, которые использует оболочка для расширения (описанная выше в разделе «Разделение слов»).
24
ответ дан 24 July 2018 в 19:27

Это всего лишь предложение и вовсе не означает, что Сергей ответит. Я думаю, что Сергей написал отличный ответ о том, почему они отличаются в печати. Как переменная в считывании назначается с остальными в переменную $c как 3 4 5 6 после 1 и 2, назначается a и b. echo не будет разделять переменную для вас, где printf будет с %d s.

Однако вы можете заставить их в основном дать вам одинаковые ответы, манипулируя эхом номера в начале команды:

В /bin/bash вы можете использовать:

echo -e "1 2 3 \n4 5 6"

В /bin/sh вы можете просто использовать:

echo "1 2 3 \n4 5 6"

Bash использует -e, чтобы включить \ escape-символы, где sh не нуждается в нем, поскольку он уже включен. \n заставляет его создать новую строку, так что теперь эхо-линия разбивается на две отдельные строки, которые теперь могут использоваться два раза для вашего оператора эхо-цикла:

:~$ echo -e "1 2 3 \n4 5 6" | while read a b c; do echo "$a, $b, $c"; done
1, 2, 3
4, 5, 6

Что, в свою очередь, создает тот же вывод с использованием команды printf:

:~$ echo -e "1 2 3 \n4 5 6" | while read a b c ;do printf "%d, %d, %d \n" $a $b $c; done
1, 2, 3 
4, 5, 6 

В sh

$ echo "1 2 3 \n4 5 6" | while read a b c; do echo "$a, $b, $c"; done
1, 2, 3
4, 5, 6
$ echo "1 2 3 \n4 5 6" | while read a b c ;do printf "%d, %d, %d \n" $a $b $c; done
1, 2, 3 
4, 5, 6 

Надеюсь, что это поможет!

7
ответ дан 22 May 2018 в 20:18
  • 1
    echo -e - это не просто расширение для POSIX, но любое echo, которое не испускает -e на его выходе, учитывая, что вход фактически игнорирует / нарушает спецификацию черных букв. (bash несовместим по умолчанию, но соответствует стандарту, когда установлены флаги posix и xpg_echo; последний может быть установлен по умолчанию во время компиляции, а это означает, что не все версии bash будет работать с echo -e, как вы ожидаете здесь). – Charles Duffy 22 July 2017 в 18:17
  • 2
    См. Разделы «ИСПОЛЬЗОВАНИЕ И ОБОСНОВАНИЕ» спецификации POSIX для echo в pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html , явно описывая, что поведение echo не указано в наличие либо -n, либо обратную косую черту в любом месте ввода, а также рекомендацию использовать printf. – Charles Duffy 22 July 2017 в 18:18
  • 3
    @CharlesDuffy Я когда-либо писал в своей книге, что я ожидаю, что это будет работать во всех версиях bash? И какая у вас проблема с моим ответом? Если вы чувствуете, что у вас есть лучшее решение, напишите его как ответ, а не пытайтесь доказать, что люди неправы. Я слишком много раз встречался с такими людьми, как вы, поэтому, пожалуйста, остановитесь с этими комментариями. Это все, что я должен сказать. – Terrance 22 July 2017 в 18:33
  • 4
    @CharlesDuffy в Ask Ubuntu мы иногда пишем ответы, которые не переносятся на другие дистрибутивы Linux. Поскольку ваш представитель здесь всего 103 пункта, вы, возможно, этого не заметили. Ваша репутация на Stack Overflow составляет 123.3K, поэтому вы, очевидно, знаете тонну вещей о системах * NIX вообще. Я думаю, что вы, Терраса и Серг, все в порядке, но смотрят на нитку под разными углами. Я эхо (не каламбур) настроение для вас написать ответ, который является * NIX портативным или, по крайней мере, переносимым через дистрибутивы Linux. – WinEunuuchs2Unix 22 July 2017 в 20:03
  • 5
    @CharlesDuffy Хотя я согласен с вашими ответами на настроение , следует сделать переносимым, это, в конце концов, сайт, ориентированный на Ubuntu, поэтому пользователи Ubuntu должны использовать определенные инструменты. Поэтому предупреждение несколько подразумевается. Давайте не будем обсуждать слишком длительные дискуссии. Вы правы, что следует учитывать другие оболочки, а также учитывать новичков, читающих их ответы. Короткий комментарий, вероятно, будет достаточным для того, чтобы сказать об этом. – Sergiy Kolodyazhnyy 23 July 2017 в 01:34

Это всего лишь предложение и вовсе не означает, что Сергей ответит. Я думаю, что Сергей написал отличный ответ о том, почему они отличаются в печати. Как переменная в считывании назначается с остальными в переменную $c как 3 4 5 6 после 1 и 2, назначается a и b. echo не будет разделять переменную для вас, где printf будет с %d s.

Однако вы можете заставить их в основном дать вам одинаковые ответы, манипулируя эхом номера в начале команды:

В /bin/bash вы можете использовать:

echo -e "1 2 3 \n4 5 6"

В /bin/sh вы можете просто использовать:

echo "1 2 3 \n4 5 6"

Bash использует -e, чтобы включить \ escape-символы, где sh не нуждается в нем, поскольку он уже включен. \n заставляет его создать новую строку, так что теперь эхо-линия разбивается на две отдельные строки, которые теперь могут использоваться два раза для вашего оператора эхо-цикла:

:~$ echo -e "1 2 3 \n4 5 6" | while read a b c; do echo "$a, $b, $c"; done 1, 2, 3 4, 5, 6

Что, в свою очередь, создает тот же вывод с использованием команды printf:

:~$ echo -e "1 2 3 \n4 5 6" | while read a b c ;do printf "%d, %d, %d \n" $a $b $c; done 1, 2, 3 4, 5, 6

В sh

$ echo "1 2 3 \n4 5 6" | while read a b c; do echo "$a, $b, $c"; done 1, 2, 3 4, 5, 6 $ echo "1 2 3 \n4 5 6" | while read a b c ;do printf "%d, %d, %d \n" $a $b $c; done 1, 2, 3 4, 5, 6

Надеюсь, что это поможет!

7
ответ дан 18 July 2018 в 09:53

Это всего лишь предложение и вовсе не означает, что Сергей ответит. Я думаю, что Сергей написал отличный ответ о том, почему они отличаются в печати. Как переменная в считывании назначается с остальными в переменную $c как 3 4 5 6 после 1 и 2, назначается a и b. echo не будет разделять переменную для вас, где printf будет с %d s.

Однако вы можете заставить их в основном дать вам одинаковые ответы, манипулируя эхом номера в начале команды:

В /bin/bash вы можете использовать:

echo -e "1 2 3 \n4 5 6"

В /bin/sh вы можете просто использовать:

echo "1 2 3 \n4 5 6"

Bash использует -e, чтобы включить \ escape-символы, где sh не нуждается в нем, поскольку он уже включен. \n заставляет его создать новую строку, так что теперь эхо-линия разбивается на две отдельные строки, которые теперь могут использоваться два раза для вашего оператора эхо-цикла:

:~$ echo -e "1 2 3 \n4 5 6" | while read a b c; do echo "$a, $b, $c"; done 1, 2, 3 4, 5, 6

Что, в свою очередь, создает тот же вывод с использованием команды printf:

:~$ echo -e "1 2 3 \n4 5 6" | while read a b c ;do printf "%d, %d, %d \n" $a $b $c; done 1, 2, 3 4, 5, 6

В sh

$ echo "1 2 3 \n4 5 6" | while read a b c; do echo "$a, $b, $c"; done 1, 2, 3 4, 5, 6 $ echo "1 2 3 \n4 5 6" | while read a b c ;do printf "%d, %d, %d \n" $a $b $c; done 1, 2, 3 4, 5, 6

Надеюсь, что это поможет!

7
ответ дан 24 July 2018 в 19:27
  • 1
    echo -e - это не просто расширение для POSIX, но любое echo, которое не испускает -e на его выходе, учитывая, что вход фактически игнорирует / нарушает спецификацию черных букв. (bash несовместим по умолчанию, но соответствует стандарту, когда установлены флаги posix и xpg_echo; последний может быть установлен по умолчанию во время компиляции, а это означает, что не все версии bash будет работать с echo -e, как вы ожидаете здесь). – Charles Duffy 22 July 2017 в 18:17
  • 2
    См. Разделы «ИСПОЛЬЗОВАНИЕ И ОБОСНОВАНИЕ» спецификации POSIX для echo в pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html , явно описывая, что поведение echo не указано в наличие либо -n, либо обратную косую черту в любом месте ввода, а также рекомендацию использовать printf. – Charles Duffy 22 July 2017 в 18:18
  • 3
    @CharlesDuffy Я когда-либо писал в своей книге, что я ожидаю, что это будет работать во всех версиях bash? И какая у вас проблема с моим ответом? Если вы чувствуете, что у вас есть лучшее решение, напишите его как ответ, а не пытайтесь доказать, что люди неправы. Я слишком много раз встречался с такими людьми, как вы, поэтому, пожалуйста, остановитесь с этими комментариями. Это все, что я должен сказать. – Terrance 22 July 2017 в 18:33
  • 4
    @CharlesDuffy в Ask Ubuntu мы иногда пишем ответы, которые не переносятся на другие дистрибутивы Linux. Поскольку ваш представитель здесь всего 103 пункта, вы, возможно, этого не заметили. Ваша репутация на Stack Overflow составляет 123.3K, поэтому вы, очевидно, знаете тонну вещей о системах * NIX вообще. Я думаю, что вы, Терраса и Серг, все в порядке, но смотрят на нитку под разными углами. Я эхо (не каламбур) настроение для вас написать ответ, который является * NIX портативным или, по крайней мере, переносимым через дистрибутивы Linux. – WinEunuuchs2Unix 22 July 2017 в 20:03
  • 5
    @CharlesDuffy Хотя я согласен с вашими ответами на настроение , следует сделать переносимым, это, в конце концов, сайт, ориентированный на Ubuntu, поэтому пользователи Ubuntu должны использовать определенные инструменты. Поэтому предупреждение несколько подразумевается. Давайте не будем обсуждать слишком длительные дискуссии. Вы правы, что следует учитывать другие оболочки, а также учитывать новичков, читающих их ответы. Короткий комментарий, вероятно, будет достаточным для того, чтобы сказать об этом. – Sergiy Kolodyazhnyy 23 July 2017 в 01:34

Другие вопросы по тегам:

Похожие вопросы: