Выполнить команду через некоторое время, если пользователь не вводит данные

cd /path/to/abc; cnt=0; for i in *.*; do mv "$i" "${PWD##*/}_$((++cnt)).${i##*.}"; done
  • для каждого каталога abc, xyz,... вы должны cdвойти в этот каталог
  • *.*используется только для выбора файлов с суффиксом
  • замените mvна echo, чтобы посмотреть, как будет выглядеть результат, прежде чем возиться

Редактировать:

Если вы хотите сделать это для нескольких каталогов, сбросьте счетчик в каждом каталоге.

Один вкладыш:

for i in */*.*; do [ "$dn" != "${i%/*}" ] && cnt=0; dn="${i%/*}"; mv "$i" "${dn}/${dn}_$((++cnt)).${i##*.}"; done

Красиво напечатано:

for i in */*.*; do
    # reset counter if different directory or dn is unset
    [ "$dn" != "${i%/*}" ] && cnt=0

    # set directory name
    dn="${i%/*}"

    # move file
    mv "$i" "${dn}/${dn}_$((++cnt)).${i##*.}"
done
7
22.09.2020, 20:16
4 ответа

Ваша попытка с sleepне сработает, поскольку вызов sleepи последующая проверка $flag_cancelпроисходят в фоновом задании. Любое изменение переменной flag_cancelв основной части кода не повлияет на значение переменной в фоновой подоболочке, и код безоговорочно приостановит работу системы через 10 секунд.

Вместо этого вы можете использовать тот факт, что и read, и selectистекают через $TMOUTсекунд в bash.

Вот вариация на тему вашего первого фрагмента кода:

suspend_maybe ()
{
        local PS3='Please confirm/cancel system suspension: '
        local TMOUT=10

        local do_suspend=true

        select confirmation in confirm cancel; do
                case $REPLY in
                        1)
                                # default case
                                break ;;
                        2)
                                do_suspend=false
                                break ;;
                        *)
                                echo 'Sorry, try again' >&2
                esac
        done

        if "$do_suspend"; then
                echo 'Suspending...'
                systemctl suspend
        else
                echo 'Will not suspend'
        fi
}

Внесены изменения:

  1. Функция теперь называется suspend_maybe, поскольку в bashуже есть встроенная -в suspendутилита.
  2. Цикл selectиспользует PS3в качестве подсказки.
  3. Тайм-аут цикла selectистекает через $TMOUTсекунд.
  4. Мы используем цифры в выражении case. Таким образом, нам не нужно вводить все строки дважды. Значение $REPLYбудет любым, что введет пользователь.
  5. Цикл selectнам нужен только для того, чтобы сообщить нам, хочет ли пользователь отменить приостановку работы системы. Мы рассматриваем приостановку как действие по умолчанию.
  6. Когда мы выходим из цикла select, мы приостанавливаем работу системы, если только пользователь не решит отменить это действие.

То же самое, но с входным контуром, использующим readв качестве отвода -вместоselect:

suspend_maybe ()
{
        local PS3='Confirm system suspension [y]/n: '
        local TMOUT=10

        local do_suspend=true

        while true; do
                if ! read -p "$PS3"; then
                        # timeout
                        break
                fi

                case $REPLY in
                        [yY]*)
                                # default case
                                break ;;
                        [nN]*)
                                do_suspend=false
                                break ;;
                        *)
                                echo 'Sorry, try again' >&2
                esac
        done

        if "$do_suspend"; then
                echo 'Suspending...'
                systemctl suspend
        else
                echo 'Will not suspend'
        fi
}

Здесь пользователь может ввести любую строку, начинающуюся с nили N, чтобы отменить приостановку. Истечение времени ожидания read, ввод слова, начинающегося с yили Y, или нажатие Ctrl+D приведет к приостановке работы системы.

В приведенном выше цикле легче поймать случай тайм-аута, если вы хотите сделать что-то особенное, когда приостановка происходит из-за того, что пользователь не отвечает на приглашение. breakв оператореif-будет запускаться всякий раз, когда вызов readтерпит неудачу, что происходит по истечении времени ожидания (или при закрытии входного потока ).

7
18.03.2021, 23:03

Вы также можете сделать это с помощью at. Преимущество :Если вам нужно освоить новый инструмент, изучите самый универсальный. atназначает команды в произвольное время в будущем. Запланированные задания можно удалить из очереди с помощью atrm.

В вашем случае:

function suspend()
{ #
    JOBNO=$(echo "systemctl suspend" | at now + 0.2 seconds 2>&1 > /dev/null | awk '{print $2}')
    echo "Please confirm/cancel system suspension:"
    select confirmation in "confirm" "cancel"; do
    case ${confirmation} in
        confirm )
            echo "System suspending..."
            systemctl suspend
            break;;
        cancel )
            echo "Canceled suspension."
        break;;
    esac
    atrm $JOBNO
    done
}
0
18.03.2021, 23:03

Можно использовать параметр tкоманды read.

Например;

read -t 5 -p "Input within 5 seconds:" data
if [[ $data ]]
then
        echo " Your input is $data"
else
        echo " You didn't any input"
fi

Запустить скрипт;

Если ничего не вводить в течение 5 секунд;

#~ bash scr.sh 
Input within 5 seconds: You didn't any input

Если ввести данные через 5 секунд;

#~ bash scr.sh
Input within 5 seconds:new data
 Your input is new data
1
18.03.2021, 23:03

В общем, у вас есть альтернатива timeoutиз GNU coreutils . Здесь не лучший выбор,потому что мы устанавливаем тайм-аут для встроенной команды, а внешняя утилита может сделать это, только создав целую оболочку:

if ! timeout 10 bash -c '
  select conf in yes no
  do
    case $conf in
      (yes) exit 1;;
      (no) exit 0;;
    esac
  done'
then
  echo 'Suspending'
fi

Вероятно, будет интереснее, если вы собираетесь запросить ввод данных от пользователя через какой-то внешний инструмент, возможно, графический (хотя некоторые из них реализуют свой собственный механизм тайм-аута ).

Обратите внимание, что для timeoutтребуется опция --foreground, если она не вызывается напрямую из приглашения оболочки (, например, если вы вызываете ее в подоболочке:( timeout... ))и ей нужно читать из терминала.

3
18.03.2021, 23:03

Теги

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