Используя массивы удара
while read -r -a words; do
prefix="${words[0]} ${words[1]}"
idx=${#words[*]}
suffix="${words[$((idx-2))]} ${words[$((idx-1))]}"
unset words[0] words[1] words[$((idx-2))] words[$((idx-1))]
middle="${words[*]}"
printf "%s %-50s %s\n" "$prefix" "${middle:0:50}" "$suffix"
done < filename
В основном это - мобильность (и надежность) проблема.
Первоначально, echo
не принял опции и ничего не развернул. Все, что это делало, производило его аргументы, разделенные пробелом и завершенные символом новой строки.
Теперь, кто-то думал, что будет хорошо, если мы могли бы сделать вещи как echo "\n\t"
производить символы новой строки или символы табуляции, или иметь опцию не произвести запаздывающий символ новой строки.
Они затем думали тяжелее, но вместо того, чтобы добавить что функциональность к оболочке (как perl
где в двойных кавычках, \t
на самом деле означает символ табуляции), они добавили его к echo
.
David Korn понял ошибку и представил новую форму кавычек оболочки: $'...'
который был позже скопирован bash
и zsh
но было слишком поздно к тому времени.
Теперь, когда стандартный UNIX echo
получает аргумент, который содержит эти два символа \
и t
, вместо того, чтобы произвести их, это производит символ табуляции. И как только это видит \c
в аргументе это прекращает производить (таким образом, запаздывающая новая строка не производится ни один).
Другие поставщики/версии оболочек/Unix приняли решение сделать это по-другому: они добавили a -e
опция развернуть escape-последовательности и a -n
опция не произвести запаздывающую новую строку. У некоторых есть a -E
для отключения escape-последовательностей некоторые имеют -n
но нет -e
, список escape-последовательностей поддерживается одной echo
реализация является не обязательно тем же, как поддерживается другим.
У Sven Mascheck есть хорошая страница, которая показывает степень проблемы.
На тех echo
реализации, что варианты поддержки, обычно нет никакой поддержки a --
отметить конец опций ( echo
встроенный из некоторых неподобных границе оболочек делают, и поддержки zsh -
для этого, хотя), так например, трудно произвести "-n"
с echo
во многих оболочках.
На некоторых оболочках как bash
¹ или ksh93
² или yash
($ECHO_STYLE
переменная), поведение даже зависит от того, как оболочка была скомпилирована или среда (GNU echo
поведение также изменится если $POSIXLY_CORRECT
находится в среде и с version4, zsh
с bsd_echo
опция, некоторые находящиеся в pdksh с их posix
опция или называют ли их как sh
или не). Так два bash
echo
s, даже от той же версии bash
как гарантируют, не будут вести себя то же.
POSIX говорит: если первый аргумент -n
или любой аргумент содержит обратные косые черты, затем поведение является неуказанным. bash
эхом в том отношении не является POSIX в этом, например, echo -e
не производит -e<newline>
поскольку POSIX требует. Спецификация UNIX более строга, она запрещает -n
и требует расширения некоторых escape-последовательностей включая \c
один, чтобы прекратить производить.
Те спецификации действительно не приходят на помощь здесь, учитывая, что много реализаций не совместимы. Даже некоторые сертифицированные системы как macOS5 не совместимы.
Для реального представления текущей действительности POSIX должен на самом деле сказать: если первый аргумент соответствует ^-([eEn]*|-help|-version)$
расширенный regexp или любой аргумент содержат обратные косые черты (или символы, кодирование которых содержит кодирование символа обратной косой черты как α
в локалях с помощью набора символов BIG5), затем поведение является неуказанным.
В целом, Вы не знаете что echo "$var"
произведет, если Вы не можете удостовериться это $var
не содержит символы обратной косой черты и не запускается с -
. Спецификация POSIX на самом деле говорит нам использовать printf
вместо этого в этом случае.
Таким образом, то, что это означает, - то, что Вы не можете использовать echo
отобразить неконтролируемые данные. Другими словами, если Вы пишете сценарий, и он берет внешний вход (от пользователя как аргументы или имена файлов от файловой системы...), Вы не можете использовать echo
отобразить его.
Это в порядке:
echo >&2 Invalid file.
Это не:
echo >&2 "Invalid file: $file"
(Хотя это будет работать хорошо с некоторыми (не совместимый UNIX) echo
реализации как bash
когда xpg_echo
как опция не включили так или иначе во время компиляции или через среду).
file=$(echo "$var" | tr ' ' _)
не в порядке в большинстве реализаций (исключение быть yash
с ECHO_STYLE=raw
(с протестом это yash
переменные не могут содержать произвольные последовательности байтов так не произвольные имена файлов), и zsh
echo -E - "$var"
6).
printf
, с другой стороны, более надежно, по крайней мере, когда это ограничено основным использованием echo
.
printf '%s\n' "$var"
Произведет содержание $var
сопровождаемый символом новой строки независимо от того, какой символ это может содержать.
printf '%s' "$var"
Произведет его без запаздывающего символа новой строки.
Теперь, также существуют различия между printf
реализации. Существует ядро функций, которое указано POSIX, но затем существует много расширений. Например, некоторая поддержка a %q
заключить аргументы в кавычки, но как это сделано, варьируется от оболочки до оболочки, некоторой поддержки \uxxxx
для unicode символов. Поведение варьируется для printf '%10s\n' "$var"
в многобайтовых локалях существует по крайней мере три различных результата для printf %b '\123'
Но в конце, если Вы придерживаетесь набора функций POSIX printf
и не пытайтесь делать что-либо, также полагают с ним, Вы вне проблемы.
Но помните, что первым аргументом является формат, так не должен содержать переменные/неконтролируемые данные.
Более надежное echo
может быть реализован с помощью printf
, как:
echo() ( # subshell for local scope for $IFS
IFS=" " # needed for "$*"
printf '%s\n' "$*"
)
echo_n() (
IFS=" "
printf %s "$*"
)
echo_e() (
IFS=" "
printf '%b\n' "$*"
)
Подоболочка (который подразумевает порождение дополнительного процесса в большинстве реализаций оболочки) может избегаться использования local IFS
со многими оболочками, или путем записи этого как:
echo() {
if [ "$#" -gt 0 ]; then
printf %s "$1"
shift
if [ "$#" -gt 0 ]; then
printf ' %s' "$@"
fi
fi
printf '\n'
}
bash
echo
поведение может быть изменено.С bash
, во время выполнения существует две вещи, которые управляют поведением echo
(около enable -n echo
или переопределение echo
как функция или псевдоним): xpg_echo
bash
опция и ли bash
находится в posix режиме. posix
режим может быть включен если bash
назван как sh
или если POSIXLY_CORRECT
находится в среде или с posix
опция:
Поведение по умолчанию в большинстве систем:
$ bash -c 'echo -n "\0101"'
\0101% # the % here denotes the absence of newline character
xpg_echo
разворачивает последовательности, поскольку UNIX требует:
$ BASHOPTS=xpg_echo bash -c 'echo "\0101"'
A
Это все еще соблюдает -n
и -e
(и -E
):
$ BASHOPTS=xpg_echo bash -c 'echo -n "\0101"'
A%
С xpg_echo
и режим POSIX:
$ env BASHOPTS=xpg_echo POSIXLY_CORRECT=1 bash -c 'echo -n "\0101"'
-n A
$ env BASHOPTS=xpg_echo sh -c 'echo -n "\0101"' # (where sh is a symlink to bash)
-n A
$ env BASHOPTS=xpg_echo SHELLOPTS=posix bash -c 'echo -n "\0101"'
-n A
На этот раз, bash
и POSIX и совместимый UNIX. Обратите внимание на это в режиме POSIX, bash
все еще не POSIX, совместимый, поскольку он не производит -e
в:
$ env SHELLOPTS=posix bash -c 'echo -e'
$
Значения по умолчанию для xpg_echo и posix могут быть определены во время компиляции с --enable-xpg-echo-default
и --enable-strict-posix-default
опции к configure
сценарий. Это обычно, что последние версии OS/X делают для создания их /bin/sh
. Никакая реализация/распределение Unix/Linux в их правильном уме обычно не делала бы это для На самом деле это не верно, /bin/bash
все же./bin/bash
та Oracle поставки с Солярисом 11 (в дополнительном пакете), кажется, создается с --enable-xpg-echo-default
(который не имел место в Солярисе 10).
ksh93
echo
поведение может быть изменено.В ksh93
, ли echo
разворачивает escape-последовательности или не и распознает, что опции зависят от содержания $PATH
и/или $_AST_FEATURES
переменные среды.
Если $PATH
содержит компонент, который содержит /5bin
или /xpg
перед /bin
или /usr/bin
компонент затем, это ведет себя путь SysV/UNIX (разворачивает последовательности, не принимает опции). Если это находит /ucb
или /bsd
сначала или если $_AST_FEATURES
7 содержит UNIVERSE = ucb
, затем это ведет себя путь BSD3 (-e
для включения расширения, распознает -n
).
Значение по умолчанию является системным иждивенцем, BSD на Debian (см. вывод builtin getconf; getconf UNIVERSE
в последних версиях ksh93):
$ ksh93 -c 'echo -n' # default -> BSD (on Debian)
$ PATH=/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /xpg before /bin or /usr/bin -> XPG
-n
$ PATH=/5binary:$PATH ksh93 -c 'echo -n' # /5bin before /bin or /usr/bin -> XPG
-n
$ PATH=/5binary:$PATH _AST_FEATURES='UNIVERSE = ucb' ksh93 -c 'echo -n' # -> BSD
$ PATH=/ucb:/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /ucb first -> BSD
$ PATH=/bin:/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /bin before /xpg -> default -> BSD
Ссылка на BSD для обработки -e
опция является немного вводящей в заблуждение здесь. Большинство из отличающихся и несовместимых echo
поведения были все представлены в AT&T:
\n
, \0ooo
, \c
в Инструментальных средствах Программиста UNIX (на основе Unix V6), и остальные (\b
, \r
...) в системе Unix IIIRef.-n
в Unix V7 (Dennis RitchieRef)-e
в Unix V8 (Dennis RitchieRef)-E
самостоятельно возможно первоначально прибыл из bash
(CWRU/CWRU.chlog в версии 1.13.5 упоминает Brian Fox, добавляющего его 18.10.1992, GNU echo
копирование его вскоре после в sh-utils-1.8 выпустило 10 дней спустя),В то время как echo
встроенный из sh
из BSDs поддерживали -e
со дня они начали использовать оболочку Almquist для него в начале 90-х, автономного echo
утилита по сей день не поддерживает его там (FreeBSD echo
все еще не поддерживает -e
, хотя это действительно поддерживает -n
как Unix V7 (и также \c
но только в конце последнего аргумента)).
Обработка -e
был добавлен к ksh93
echo
когда во вселенной BSD в ksh93r версии, выпущенной в 2006 и, может быть отключен во время компиляции.
Начиная с coreutils 8.31 (и эта фиксация), GNU echo
теперь разворачивает escape-последовательности по умолчанию, когда POSIXLY_CORRECT находится в среде, для соответствия поведению bash -o posix -O xpg_echo
echo
встроенный (см. отчет об ошибках).
echo
Большинство версий macOS получило сертификацию UNIX от OpenGroup.
Их sh
встроенный echo
совместимо, как это bash
(очень старая версия) созданный с xpg_echo
включенный по умолчанию, но их автономное echo
утилита не. env echo -n
ничего не производит вместо -n<newline>
, env echo '\n'
выводы \n<newline>
вместо <newline><newline>
.
Это /bin/echo
тот из FreeBSD, который подавляет вывод новой строки, если первый аргумент -n
или (с 1995) если последний аргумент заканчивается в \c
, но не поддерживает никакие другие последовательности обратной косой черты, требуемые UNIX, даже \\
.
echo
реализации, которые могут произвести произвольные данные дословноСтрого говоря Вы могли также считать это FreeBSD/macOS /bin/echo
выше (не их оболочка echo
встроенный), где zsh
echo -E - "$var"
или yash
ECHO_STYLE=raw echo "$var"
(printf '%s\n' "$var"
) мог быть записан:
/bin/echo "$var
\c"
И zsh
echo -nE - "$var"
(printf %s "$var"
) мог быть записан
/bin/echo "$var\c"
Реализации та поддержка -E
и -n
(или может быть настроен к), может также сделать:
echo -nE "$var
"
Для эквивалента printf '%s\n' "$var"
.
_AST_FEATURES
и AST UNIVERSE
_AST_FEATURES
не предназначен, чтобы управляться непосредственно, это используется для распространения параметров конфигурации AST через выполнение команды. Конфигурация предназначена, чтобы быть сделанной через (недокументированный) astgetconf()
API. Внутри ksh93
, getconf
встроенный (включил с builtin getconf
или путем вызова command /opt/ast/bin/getconf
) интерфейс к astgetconf()
Например, Вы сделали бы builtin getconf; getconf UNIVERSE = att
измениться UNIVERSE
установка на att
(порождение echo
вести себя SysV путь среди прочего). После выполнения этого Вы заметите $_AST_FEATURES
переменная среды содержит UNIVERSE = att
.
Вы могли бы хотеть использовать printf
для его параметров форматирования. echo
полезно когда дело доходит до печати значения переменной или (простой) строки, но вот и все. printf
может в основном сделать то, что может сделать версия C его.
Использование в качестве примера и возможности:
Echo
:echo "*** Backup shell script ***"
echo
echo "Runtime: $(date) @ $(hostname)"
echo
printf
:vech="bike"
printf "%s\n" "$vech"
Источники:
echo
распечатать переменную может перестать работать, если значение переменной содержит метасимволы.
– Keith Thompson
29.04.2013, 18:22
Одно "преимущество", если бы Вы хотите назвать его, что, состояло бы в том, что Вы не должны говорить это как echo
интерпретировать определенные escape-последовательности такой как \n
. Это знает для интерпретации их и не потребует -e
сделать так.
printf "some\nmulti-lined\ntext\n"
(NB: последнее \n
необходимо, echo
подразумевает его, если Вы не даете -n
опция)
по сравнению с
echo -e "some\nmulti-lined\ntext"
Отметьте последнее \n
в printf
. В конце дня это - вопрос вкуса и требований, что Вы используете: echo
или printf
.
/usr/bin/echo
и bash
встроенный. dash
, ksh
и zsh
встроенный echo
не нуждается -e
переключатель для расширения оставленных из обратной косой черты символов.
– manatwork
23.02.2013, 12:35
Одним из недостаток PrintF
- это производительность, поскольку встроенная оболочка ECHO
намного быстрее. Это входит в игру, особенно в Cygwin, где каждый экземпляр новой команды вызывает накладные расходы на тяжелые окна. Когда я изменил свою эхо-тяжелую программу с использованием / BIN / ECHO
к эхо-эхоте, производительность почти удвоилось. Это торговля между портативностью и производительностью. Это не удам данка, чтобы всегда использовать Printf
.
echo
расширьтесь\x
последовательности в противоположность оболочке как часть синтаксиса заключения в кавычки - то, что можно затем произвести байт NUL (другой возможно, неправильный дизайн Unix является теми строками разграниченных пустым указателем, где половина системных вызовов (какexecve()
) не может взять произвольные последовательности байтов), – Stéphane Chazelas 04.08.2015, 15:15