Ответы:
Обновленный ответ для более общего решения. см. также мой другой ответ ниже, используя только расширение скобки и pritnf
.
$ str='Hello World!'
$ sed -r ':loop; s/ (=*):$/\1=:/; t loop' <<< "$(printf '%-20s:\n' "$str" )"
Hello World!========:
Как это устроено?
это (=*):$/
захватывает один пробел, один или более =
, за которым следует двоеточие :
в конце ввода; мы делаем набор =
как групповое совпадение и \1
будем его обратной ссылкой.
С помощью :loop
мы определили названную метку loop
и вместе с t loop
ней перейдем к этой метке, когда a s/ (=*):$/\1=:/
выполнит успешную замену;
В замене с помощью \1=:
, он всегда будет увеличивать число =
s и возвращать само двоеточие до конца строки.
filler='===================='
string='foo'
printf '%s\n' "$string${filler:${#string}}"
дает
foo=================
${#string}
длина значения $string
и ${filler:${#string}}
подстрока $filler
от смещения ${#string}
вперед.
Общая ширина вывода будет равна максимальной ширине $filler
или $string
.
Строка-заполнитель может в системах jot
, которые создаются динамически с использованием
filler=$( jot -s '' -c 16 '=' '=' )
(по 16 =
в строке). Системы GNU могут использовать seq
:
filler=$( seq -s '=' 1 16 | tr -dc '=' )
Другие системы могут использовать Perl или какой-либо другой более быстрый способ динамического создания строки.
printf
для генерации фильтра, который почти доступен во всех системах, и расширение скобок с подобными оболочками bash/szh
?
printf
расширением + скобка bash
?
printf "%.20s:\n\n" "$str========================="
где %.20s
формат усечения строки
Один из способов сделать это:
printf "====================:\r%s\n\n" 'hello world!!'
====================\rhello world
, что может быть проблемой, если оператору нужно сохранить это, а не просто напечатать его на экране.
echo -e '=================\rHello World!!'
, но имеет ту же проблему, на которую указал @terdon.
echo
поддерживает -e
. printf
почти всегда лучше, чем echo
по многим причинам.
Подход Perl:
$ perl -le '$k="hello world!!"; while(length($k)<20){$k.="=";} print "$k\n"'
hello world!!=======
Или лучше @SatoKatsura отметил в комментариях:
perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'
Если вам нужно поддерживать многобайтовые символы UTF, используйте:
PERL_UNICODE='AS' perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'
Та же идея в оболочке:
v='hello world!!'; while [ ${#v} -lt 20 ]; do v="$v""="; done; printf '%s\n\n' "$v"
perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'
. Однако это (и все другие решения, опубликованные до сих пор) ломаются, если задействованы многобайтовые символы.
perl6
может быть способ сделать это правильно, даже с многобайтовыми символами. Но с другой стороны perl6
это раздражает во многих отношениях.
PERL_UNICODE='AS'
. Например: printf '%s' nóóös | perl -nle 'print length($_)'
печатает 8 («неправильно»), а printf '%s' nóóös | PERL_UNICODE='AS' perl -nle 'print length($_)'
печатает 5 («правильно»).
Другой способ заключается в использовании только printf
команды и генерировать шаблон символов дополнени сначала Shell Brace Expansion
(Вы можете положить конец с номером ≥ Форматирование области вы хотите напечатать в {1..end}
) и получить только каждый первый символ этого , %.1s
который является =
s , а затем напечатать длину только первые 20 символов область этого %.20s
. Это своего рода лучший способ иметь повторяющиеся символы / слова вместо их дублирования.
printf '%.20s:\n' "$str$(printf '%.1s' ={1..20})"
Hello World!!=======:
Пояснения:
Обычно, как Brace Expansion , оболочка расширяется {1..20}
следующим образом, если мы печатаем их.
printf '%s ' {1..20}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Таким образом, при добавлении к нему знака равенства ={1..20}
оболочка будет расширяться следующим образом.
printf '%s ' ={1..20}
=1 =2 =3 =4 =5 =6 =7 =8 =9 =10 =11 =12 =13 =14 =15 =16 =17 =18 =19 =20
И printf '%.1s'
это означает printf '%WIDE.LENGTH'
, что мы печатаем только одну ДЛИНУ из тех , что указаны выше, по умолчанию 1
WIDE . так приведут =
только s и 20 раз повторились.
Теперь, когда printf '%.20s:\n'
мы печатаем только длину 20, $str
а если длина $str
<20, остальная часть будет =
заполняться из сгенерированных s вместо пробелов.