Как повторить тире (дефис) в оболочке

Как я могу повторить символ - n раз в оболочке? Я прочитал и попробовал этот, но это не работает для -. Он выдает ошибку invalid option. Ниже приведена точная команда, которую я использовал:

printf '-%.0s' {1..100}

Исходная строка: printf '-%0.s' {1..100}

Я также попытался выполнить -, поставив \, но в этом случае он повторяет \- n раз.

Ответ 1

Это вызывает ошибку:

$ printf '-%.0s' {1..100}; echo ""
bash: printf: -%: invalid option
printf: usage: printf [-v var] format [arguments]

Это работает отлично под bash:

$ printf -- '-%.0s' {1..100}; echo ""
----------------------------------------------------------------------------------------------------

Для других оболочек попробуйте:

printf -- '-%.0s' $(seq 100); echo ""

Проблема заключалась в том, что printf ожидает, что - запускает параметр. Как обычно среди утилит Unix/POSIX в этом типе ситуации, -- сигнализирует printf, чтобы ожидать больше опций.

Ответ 2

Полезный ответ John1024 предоставляет общее решение, которое показывает, как устранить ошибки из операндов для всех утилит, подобных POSIX.

В данном случае самое простое решение (работает не только в bash, но и в ksh и zsh):

printf '%.0s-' {1..100}

Размещение %.0s до - позволяет избежать ошибки ввода начального - для параметра.

Немного оптимизировано: [1]

printf '%.s-' {1..100}

[1] %.0s на практике является самой переносимой формой (чтобы быть полностью переносимой, вы также должны избегать расширения скобок {...}).
%.s эквивалентная сокращенная форма поддерживается bash, ksh и dash, но не zsh <= v5.2 - даже если это равно POSIX-совместимый: "Точность [часть после .] должна иметь форму ('. '), за которым следует десятичная цифра, строка нулевой цифры обрабатывается как ноль."

В качестве бокового примечания: вопрос первоначально содержал доброкачественную (в Bash) опечатку, которая вызвала дебаты: %0.s вместо %.0s: %0.s должен эффективно быть таким же, как %.0s, и, если на то пошло, то же самое, что и %.s и %0.0s (все эффективно запросят: напечатайте поле [минимальной нулевой ширины], заполненное строкой нулевой длины), но на практике это 't: zsh <= v5.2 не обрабатывает %0.s правильно (опять же, из-за части .s).
Аналогично, GNU printf реализация внешней утилиты (/usr/bin/printf), как и GNU coreutils v8.24, сообщает об ошибке с %0.s, поскольку она обычно не принимает ширину поля 0 с s: invalid conversion specification - это относится к менее известным оболочкам, которые не предоставляют printf как встроенный. Обратите внимание, что реализация BSD/OSX не имеет этой проблемы.
Оба поведения zsh (< = v5.2) с поведением %.s и GNU /usr/bin/printf с %0s являются отклонениями от спецификации POSIX, которые пахнут как ошибки.
Этот вопрос запрашивает поведение zsh относительно %.s, и ошибка с тех пор была подтверждена и сообщается как фиксированный через post-v5.2 commit, который еще не выпущен на момент написания этой статьи.

Ответ 3

Используйте цикл for и диапазон номеров:

for i in {1..10}; 
    do echo "-"; 
done

Или в одной строке:

for i in {1..10}; 
    do echo -n "-"; 
done

который выводит ----------.

EDIT: это было до вашего редактирования printf.

Ответ 4

Я бы рекомендовал использовать традиционный цикл for, так как нет необходимости создавать подпроцессы или расширять 100 аргументов:

N=100
for((i = 0; i < $N; ++i)); do
  printf -
done

Любопытно, что printf -%s запускает "недопустимую опцию", но printf - нет. Возможно, чтобы быть более безопасным, вы могли бы сделать printf %s -.

Ответ 5

  • jot может сделать это без багизмов:

    jot -s '' -b - 100
    
  • seq тоже, но не так, ему нужен tr:

    seq -s- 100 | tr -d '[0-9]'
    

Ответ 6

Вы также можете использовать tput вместе с printf, чтобы выполнить заполнение терминала точным количеством тире, либо напрямую рисовать строку, либо записать строку штрихов в переменную (например, line) для повторения использование, например чтобы написать строку ширины экрана тире к переменной line, вы могли бы сделать:

$ eval printf -v line '%.0s-' {1..$(tput cols)}

а затем просто echo "$line" каждый раз, когда вам нужно нарисовать линию. Вы также можете записать его непосредственно на экран с помощью.

$ eval printf '%.0s-' {1..$(tput cols)}

(Я не большой поклонник eval, но это одно использование, когда вам гарантировано, что результат команды не может быть вредным).

Ответ 7

Это было моей идеей в течение многих лет... но не для AIX. Изменить последний символ, чтобы изменить повторяющийся символ, который составляет строку

printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' _