BASH разделить переменную на символы и распечатать пробел в цикле for

Я пытаюсь создать необычное приветственное сообщение, которое будет отображаться при открытии терминала. Я сделал это на Java с этим кодом:

public void slowPrint() {
    String message = "Welcome, " + System.getProperty("user.name");

    try {
        for(int i = 0; i < message.length(); i++) {
            System.out.print(message.charAt(i));
            Thread.sleep(50);
        }
    } catch(InterruptedException ex) {
        ex.printStackTrace();
    }
}

Теперь я довольно новичок в bash, но мне удалось сделать этот код:

for i in W e l c o m e , $USER; do
    echo -ne $i
    sleep 0.05
done

echo !

Есть две проблемы с этим кодом:

  1. Я понятия не имею, как напечатать пробел после запятой, вывод просто Welcome,simon! Как я могу сделать так, чтобы он выводил пробел?
  2. Это, конечно же, печать $USER как целое слово. Я хотел бы, чтобы это было символ за персонажем, как я могу это сделать?

3 ответа

Решение

Вы можете использовать стандартный цикл for для достижения того же эффекта:

MESSAGE="Welcome, $USER"
for (( i=0; i<${#MESSAGE}; i++ )); do
    echo -ne "${MESSAGE:$i:1}"
    sleep 0.05
done
echo !

${MESSAGE:$i:1} синтаксис принимает подстроку 1 из позиции i в строке. Заключение этой части в кавычки гарантирует, что такие вещи, как пробелы и табуляции также будут напечатаны.

Вы можете указать пространство достаточно легко; заключите его в кавычки:

for i in W e l c o m e , ' ' ...

расщепляющий $USER на отдельных персонажей можно сделать много способов. То, как я бы это сделал, старомодно, но надежно:

for i in W e l c o m e , ' ' $(sed 's/./& /g' <<< "$USER")

Обратите внимание, что <<< операция спасает процесс и трубу; он перенаправляет стандартный ввод sed поэтому он читает данную строку как строку ввода.

Или, если вы думаете, что имя пользователя может содержать пробелы или другие специальные символы:

for i in W e l c o m e , ' ' $(sed "s/./'&' /g" <<< "$USER")

(Это не пуленепробиваемый; значение USER="Tam O'Shanter" вызовет некоторое горе, и простое решение для этого сталкивается с проблемой USER='Will "O'\''Wisp" Light' вместо.... бормотание, бормотание, тайные заклинания, ...

    for i in W e l c o m e , ' ' $(sed "s/./'&' /g; s/'''/\\\\'/g" <<< "$USER")

за исключением того, что имя повторяется в одинарных кавычках вокруг всего; ворчать, ворчать, ... я думаю, я только что понял, почему я никогда не смогу сделать это одновременно... пробелы тоже мешают... Я бы использовал простую первую версию и сказал бы людям, что нет использовать пробелы или специальные символы в значении $USER.)

Могут быть способы сделать это без вызова отдельного процесса, такого как sed; см. ответ heuristicus. Так что делай так. Но учтите, что он прочно привязан к bash таким образом, что этот ответ не полностью связан с bash - вы можете легко заменить <<< обозначение (которое является bash -только с echo "$USER" | ... вместо.

Полностью POSIXly переносимый, то есть без этих надоедливых ударов и без разветвлений в sed:

#!/bin/sh

m="Welcome, $USER!"
while test ${#m} -gt 0; do
  r=${m#?}
  printf '%s ' "${m%%$r}"
  m=$r
  sleep 0.05
done
printf '\n'

Обратите внимание, что спать на доли секунды непереносимо.

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