nixp.ru v3.0

19 января 2017,
четверг,
03:18:04 MSK

DevOps с компанией «Флант»
anonymous написал 18 июля 2004 года в 14:46 (884 просмотра) Ведет себя неопределенно; открыл 1814 темы в форуме, оставил 5575 комментариев на сайте.

Помогите написать прогу, что когда нажимаешь на printscreen на рабочем столе появляется скриншот с номером один, если еще раз нажать то уже номер два и так далее.

вот заготовочка, осталось дописать только операцию с if

anonymous

#!/bin/sh

import -window root ~/Desktop/$screen.png

sas

Один из вариантов ниже. Усовершенствуйте сами.

#!/bin/bash
target_dir=~/Desktop
cd $target_dir
no=$(ls *.png | sort -t '-' -k 1,1nr | head -n 1 | sed -e 's/-screen\..*//')
if [ "$no" = "" ]; then
   no=1
else
   no=$(($no+1))
fi
import -window root $target_dir/$no-screen.png

Удачи

— sas

anonymous

Спасибо, ща будем разбираться

anonymous

Ну вот черновой рабочий вариант

#!/bin/bash

target_dir=~/Desktop

no=$(ls ~/Desktop | sort -t '.' -k 1,1nr | head -n 1 | sed -e ’s/\..*//’)

if [ "$no" = "" ]; then

no=1

else

no=$(($no+1))

fi

import -window root ~/Desktop/$no-screen.png

А скажите что означает вот такая палочка |

и может знаете как в kde отключить появление ksnapshot при нажатии на PrintScreen, и назначить этой кнопочки свою команду

Genie

| — это «перенаправление» вывода обной программы на вход другой.

один из наиболее часто используемых взаимодействий программ в unix среде.

подробнее об этом — `man sh` на слове Pipeline

Pipelines

A pipeline is a sequence of one or more commands separated by the character |. The format for a pipeline is:

[time [-p]] [ ! ] command [ | command2 ... ]

The standard output of command is connected via a pipe to the standard input of command2. This connection is performed before any redirections specified by the command (see REDIRECTION below).

If the reserved word ! precedes a pipeline, the exit status of that pipeline is the logical NOT of the exit status of the last command. Otherwise, the status of the pipeline is the exit status of the last command. The shell waits for all commands in the pipeline to terminate before returning a value.

If the time reserved word precedes a pipeline, the elapsed as well as user and system time consumed by its execution are reported when the pipeline terminates. The -p option changes the output format to that specified by POSIX. The TIMEFORMAT variable may be set to a format string that specifies how the timing information should be displayed; see the description of TIMEFORMAT under Shell Variables below.

Each command in a pipeline is executed as a separate process (i.e., in a subshell).

Т.е. это означает, что программы запускаются все вместе, и создаётся «канал» для передачи выходных данных программы слева от | программе справа.

Uncle Theodore
aivss
и может знаете как в kde отключить появление ksnapshot при нажатии на PrintScreen, и назначить этой кнопочки свою команду

Посмотри в kcontrol в «Региональных и специальных возможностях» раздел «Привязка клавиш». Там же написано, как свою программу в меню записать.

Good Luck,

UT

anonymous

А вот к примеру даю такую команду rpm -qa *

как мне вывод записать в файл? как с помощью cat создать текстовый файл?

весь kcontrol облазил, даже намека на printscreen не наше

Uncle Theodore
aivss
А вот к примеру даю такую команду rpm -qa *

как мне вывод записать в файл?

Текстовый файл не имеет стандартного ввода, поэтому пайпом в него вывод программы не загонишь. Но есть два типа редиректа для записи stdout в файл: > и >> Первая переписывает файл с начала, вторая — добывляет к концу

rpm -qa * >> textfile.txt

как с помощью cat создать текстовый файл?

cat file1.txt > file2.txt

или ты имел в виду, как с помощью echo создать текстовый файл?

весь kcontrol облазил, даже намека на printscreen не наше

Хм, а если ты нажмешь Prnt Scrn, то выскочит ksnapshot? Интересно, где ж она тогда привязана? Ты под KDE работаешь?

Good Luck,

UT

anonymous

под kde.

когда нажимаешь printscreen то вылезает ksnapshot

xant
aivss
под kde.

когда нажимаешь printscreen то вылезает ksnapshot

Не это?

Regional & access -> Keyboard shortcuts -> Global shortcuts — > Miscellanous -> desktop screenshot

anonymous

не то

Genie

В таком случае, видимо, придётся сменить KDE на более гибкое ;)

Это не означает, что надо так же снести все остальные программы, использующие kde lib. Просто KDE предполагает наличие у пользователя «средних» потребностей. И под них, соответственно, и настроен. Это может и хорошо, но вот.. Свободы настройки куда как меньше.

В общем, меняй kde на какой-нибудь *wm, и задавай вопросики по настройке оного уже в них ;)

Master

Можно сказать мой окончательный вариант:

#!/bin/bash
no=$(ls -r | grep screen_.*.png | head -n 1 | sed -e 's/screen_//' | sed -e 's/.png//')
if [ "$no" = "" ]; then
   no=1
else
   no=$(($no+1))
fi
echo "Write file screen_$no.png"
import -window root screen_$no.png
sas

Если Вы хотите достичь следущего:

1) Спасать скриншоты в какой-то один каталог

2) Получать имя файла для скриншота по правилу: «screen_» + counter + «.png», где counter увеличивается на 1 каждый раз при спасении файла

то Ваш вариант работать правильно к сожалению не будет потому что:

1) «ls -r» — Не будет правильно сортировать файлы.

Например:

# mkdir /tmp/tst

# cd /tmp/tst

# i=1

# while [ $i -lt 21 ]; do

touch screen_$i.png

i=$(($i+1))

done

ls -r

Обратите внимание на порядок файлов screen_1.png screen_10 и т.д.

Можно попробывать использовать «ls -t», но и это будет работать только в случае если системное время не будет меняться и Вы не будете вызывать скрипт в пределах 1 секунды. :)

Самое надежное в этом случае использовать sort и правило для имени:

«screen_» + counter + «_.png»

'_’ — sort может использовать как ограничители полей

2) Вам тут grep после ls не нужен. Зачем лишний процесс стартовать?

3) Вместо 2-х sed нужен 1

Т.е. предлагаю следующий вариант (не тестирован):

#!/bin/bash
dir=/tmp/tst
cd $dir
no=$(ls screen_*_.png | sort -t '_' -k 2,2nr | head -n 1 | sed -e 's/[^0-9]//g')
if [ -z $no ]; then
   no=1
else
   no=$((no+1))
fi
import -window root screen_$no_.png

Успехов

— sas

PS Теоретически у предложенного вырианта тоже могут быть проблемы, если более чем один скрипт запущен в системе одновременно. Лечение на уровне скрипта — наверное утилита lockfile (man lockfile). Она входит в sendmail, если не ошибаюсь.

Master

1) скриншоты создаются в каталоге и которого запускается скрипт

2) grep нужен для того чтобы ls не выводил сообщение об отстутствии *.png файлов (в каталоге и которого запускается скрипт).

3) ls -t у меня работать будет, поскольку время работы import этого скрипта у меня порядка 3-х секунд.

Итоговый вариант:

#!/bin/bash
no=$(ls -t | grep screen_.*.png | head -n 1 | sed -e 's/[^0-9]//g')
if [ -z $no ]; then
   no=1
else
   no=$(($no+1))
fi
echo "Write file screen_$no.png"
import -window root screen_$no.png
sas
Master
1) скриншоты создаются в каталоге и которого запускается скрипт

2) grep нужен для того чтобы ls не выводил сообщение об отстутствии *.png файлов (в каталоге и которого запускается скрипт).

3) ls -t у меня работать будет, поскольку время работы import этого скрипта у меня порядка 3-х секунд.

Итоговый вариант:

#!/bin/bash
no=$(ls -t | grep screen_.*.png | head -n 1 | sed -e 's/[^0-9]//g')
if [ -z $no ]; then
   no=1
else
   no=$(($no+1))
fi
echo "Write file screen_$no.png"
import -window root screen_$no.png

Нам лишнего не надо :)

#!/bin/bash
file_prefix="screen_"
file_ext="png"
no=$(ls -t ${file_prefix}*.${file_ext} 2>/dev/null | head -n 1 | sed -e 's/[^0-9]//g')
if [ -z $no ]; then
   no=1
else
   no=$(($no+1))
fi
target="${file_prefix}${no}.${file_ext}"
echo "Write file ${target}"
import -window root ${target}

А пользователю ведь никто не запретит по мышке или по Enter быстро нажимать, поэтому лучше sort. И кстати зачем же писать скрипты, которые на быстродействие конкретной машины и видео режим завязаны? Сами же и навернетесь когда нибудь или Ваши друзья/клиенты. Настоятельно рекомендую хотя бы lockfile использовать.

Удачи

— sas

Master

— Используется lockfile и «ls -r»

— Не удалось уйти от двух sed’ов

#!/bin/bash
lock_prefix="/tmp/screen.lock"
lock_suffix=`eval date +%s`
lockfile="${lock_prefix}.${lock_suffix}"
lockfile $lockfile
file_prefix="screen_"
file_ext="png"
no=$(ls -r ${file_prefix}*.${file_ext} 2>/dev/null | head -n 1 | sed -e 's/[^0-9]//g' | sed -e 's/^0*//')
if [ -z $no ]; then
    no="1"
else
    no=$(($no+1))
fi
if [ $no -lt "100" ]; then
    no="0${no}"
fi
if [ $no -lt "10" ]; then
    no="0${no}"
fi
target="${file_prefix}${no}.${file_ext}"
echo "Write file ${target}"
import -window root ${target}
rm -f $lockfile
sas
Master
— Используется lockfile и «ls -r»

— Не удалось уйти от двух sed’ов

#!/bin/bash
lock_prefix="/tmp/screen.lock"
lock_suffix=`eval date +%s`
lockfile="${lock_prefix}.${lock_suffix}"
lockfile $lockfile
file_prefix="screen_"
file_ext="png"
no=$(ls -r ${file_prefix}*.${file_ext} 2>/dev/null | head -n 1 | sed -e 's/[^0-9]//g' | sed -e 's/^0*//')
if [ -z $no ]; then
    no="1"
else
    no=$(($no+1))
fi
if [ $no -lt "100" ]; then
    no="0${no}"
fi
if [ $no -lt "10" ]; then
    no="0${no}"
fi
target="${file_prefix}${no}.${file_ext}"
echo "Write file ${target}"
import -window root ${target}
rm -f $lockfile

1. И самое важное lockfile то у Вас так работать не будет, т.к. для каждого процесса создается с «почти» уникальным именем. Вы хотели заблокировать запуск более одного процесса в течении 1-ой секунды, но это не пройдет в некоторых случаях.

Правильное решение:

* Имя файла должно быть одинаково для всех процессов

* Если скрипт будет прерван по каким либо причинам (например Ctrl+C), то Ваш лок не будет удален. Решение проблемы — использование trap

2. У Вас существует ограничение на число уникальных файлов скриншотов в одном директории (max == 999). Это ограничение искусственное и в принципе никому не нужное, хотя число файлов и велико. Существуют как мне кажется следующие решения (в порядке от наименее предпочтительных к более):

* Как минимум надо пользователю сказать, что число файлов превысило максимальное и скрипт работать не будет (+код выхода != 0)

* Сказать пользователю, что после 999 файла будем перезаписывать начиная с 1-го (+код выхода != 0), что тоже не очень удобно, т.к. пользователю в этом случае сложней найти нужный скриншот

* Как я уже говорил 3 раза — используйте sort и этой проблемы не будет вообще

3) Второй sed не нужен:

# i=00132

# i=$(($i+1))

будет работать и так

Если Вы все-таки хотите использовать 999 ограничение или 9999 :), то используйте команду printf

printf '%04d\n' $i

4) Ваше lock_suffix=`eval date +%s` — то же самое, что и lock_suffix=`date +%s` или, более наглядно lock_suffix=$(date +%s)

Успехов

— sas

Master

— Использую trap

— Использую printf

— Предупреждаю пользователя

— Второй sed нужен. Без него (у меня) при $no=0008, $no на единицу увеличиваться не хочет.

#!/bin/bash
lockfile="/tmp/screen.lock"
trap "rm -f ${lockfile}" INT
lockfile ${lockfile}
file_prefix="screen_"
file_ext="png"
no=$(ls -r ${file_prefix}*.${file_ext} 2>/dev/null | head -n 1 | sed -e 's/[^0-9]//g' | sed -e 's/^0*//')
if [ -z $no ]; then
    no="1"
else
    if [ $no = "999" ]; then
        echo "Delete screenshot!!!"
        rm -f ${lockfile}
        exit -1
    fi
    no=$(($no+1))
fi
target=`printf 'screen_%04d.png\n' $no`
echo "Write file ${target}"
import -window root ${target}
rm -f ${lockfile}
sas
Master
— Использую trap

— Использую printf

— Предупреждаю пользователя

— Второй sed нужен. Без него (у меня) при $no=0008, $no на единицу  увеличиваться не хочет.

Good  :)  Much better. Sorry for 0+. My fault.  :(

Warning: was not tested.

#!/bin/bash
# --- Error codes.
ERR_LOCK=-1
ERR_MAX_NO=-2
# --- maximum number of the screenshots
MAX_NO=9999
# --- lockfile related
TIMEOUT=10
RETRIES=1
lockfile="/tmp/screen.lock"
# --- target file related
file_prefix="screen_"
file_ext="png"
# --- Ok, starting
trap "rm -f ${lockfile}" INT
lockfile -${TIMEOUT} -r ${RETRIES} ${lockfile} 2>/dev/null
if [ $? -ne 0 ]; then
    echo "Cannot lock!" >&2
    exit ERR_LOCK
fi
# --- 1 sed
no=$(ls -r ${file_prefix}*.${file_ext} 2>/dev/null | head -n 1 | sed -e 's/[^0-9]//g; s/^0*//')
if [ -z $no ]; then
    no="1"
else
    # --- If printf '%04d, then not 999 but 9999
    if [ $no -eq ${MAX_NO} ]; then
        echo "Delete screenshot!!!" >&2
        rm -f ${lockfile}
        exit ERR_MAX_NO
    fi
    no=$(($no+1))
fi
target=$(printf 'screen_%04d.png\n' $no)
#
# --- to make script a little bit more responsive we should not wait until import is
#      finished. Just "reserve" our file and remove the lock, so next process can
#      start faster
#
touch $target
rm -f ${lockfile}
echo "Write file ${target}"
import -window root ${target}

Good luck

— sas

Genie

no=$(ls -r ${file_prefix}*.${file_ext} 2>/dev/null | head -n 1 | sed -e ’s/[^0-9]//g' | sed -e ’s/^0*//’)

заменить на

no=$(/bin/ls -r ${file_prefix}[0-9]{1,4}.${file_ext} 2>/dev/null | head -n 1 | sed -r ’s/^[^1-9]*([0-9]+)[^0-9]*$/\1/g’)

/bin/ls — во избежание alias

regexp у sed — ну, и так понятно

sas
Genie
no=$(ls -r ${file_prefix}*.${file_ext} 2>/dev/null | head -n 1 | sed -e ’s/[^0-9]//g' | sed -e ’s/^0*//’)

заменить на

no=$(/bin/ls -r ${file_prefix}[0-9]{1,4}.${file_ext} 2>/dev/null | head -n 1 | sed -r ’s/^[^1-9]*([0-9]+)[^0-9]*$/\1/g’)

/bin/ls — во избежание alias

regexp у sed — ну, и так понятно

Классное дополнение. Спасибо. Только последнее g в sed не нужно, т.к. используются ^ и $

Успехов

— sas

vnp
Genie
no=$(ls -r ${file_prefix}*.${file_ext} 2>/dev/null | head -n 1 | sed -e ’s/[^0-9]//g' | sed -e ’s/^0*//’)

заменить на

no=$(/bin/ls -r ${file_prefix}[0-9]{1,4}.${file_ext} 2>/dev/null | head -n 1 | sed -r ’s/^[^1-9]*([0-9]+)[^0-9]*$/\1/g’)

/bin/ls — во избежание alias

regexp у sed — ну, и так понятно

Тогда уж и head уберите:

no=$(/bin/ls -r ${file_prefix}[0-9]{1,4}.${file_ext} 2>/dev/null | sed -r '1s/^[^1-9]*([0-9]+)[^0-9]*$/\1/g')
Genie
vnp
Тогда уж и head уберите:

И получим, скажем, строку «990 screenshot_989.png screenshot_988.png …»

Кстати, немного я ошибся.

Нет в shell возможности указать сколько символов смотреть, поэтому:

no=$(/bin/ls -r ${file_prefix}*.${file_ext} 2>/dev/null | head -n 1 | sed -r 's/^[^1-9]*([0-9]+)[^0-9]*$/\1/')

head и sed тоже желательно бы оградить от переопределения их в alias…

как-нибудь так:

PATH=/bin:/usr/bin
$LS=`which ls` || exit -2 # это значит, что не нашли
$HEAD=`which head` || exit -2
$SED=`which sed` || exit -2
no=$($LS -r ${file_prefix}*.${file_ext} 2>/dev/null | $HEAD -n 1 | $SED -r 's/^[^1-9]*([0-9]+)[^0-9]*$/\1/')
vnp
Genie
И получим, скажем, строку «990 screenshot_989.png screenshot_988.png …»

Ну опечатка, конечно. -n забыл. Или q в команде. По вкусу, в общем.

sas
Genie
И получим, скажем, строку «990 screenshot_989.png screenshot_988.png …»

Кстати, немного я ошибся.

Нет в shell возможности указать сколько символов смотреть, поэтому:

no=$(/bin/ls -r ${file_prefix}*.${file_ext} 2>/dev/null | head -n 1 | sed -r 's/^[^1-9]*([0-9]+)[^0-9]*$/\1/'){/code]
head и sed тоже желательно бы оградить от переопределения их в alias...
как-нибудь так:
 [code]PATH=/bin:/usr/bin
$LS=`which ls` || exit -2 # это значит, что не нашли
$HEAD=`which head` || exit -2
$SED=`which sed` || exit -2
no=$($LS -r ${file_prefix}*.${file_ext} 2>/dev/null | $HEAD -n 1 | $SED -r 's/^[^1-9]*([0-9]+)[^0-9]*$/\1/')
[/code]

Ну я думаю, что все таки лучше и правда ограничить ls в этом случае:

ls -r $file_prefix[0-9][0-9][0-9][0-9].$file_ext (т.к. выбрана схема в которой мы заранее знаем сколько цифр в числе.Недостаток этого ограничения обсуждать не предлагаю :) )

Это важно в случае, если в директории есть например файл с именем screen_creen.png, то наш номер всегда будет равен 1

Или можно вернуться к предложенному Master-ом grep после ls

Кроме того, все таки, по размышлении, я бы использовал sed -e ’s/[^0-9]//g; s/^0*//' без расширенных регулярных варажений из-за портабельности, т.к. не все sed их поддерживают.

Это только мнение :)

Удачи

— sas

Genie

поэкспериментировал я тут немного… ;)

получилось вот такое ;)

правда — на перле, что малость удобнее и проще.

ИБО: Атомарный лок в shell — сделать сложно.

#!/usr/bin/perl
use Fcntl qw(:DEFAULT :flock);
$lockfile="/var/lock/screenshot.lock";
$ss_folder=".";
$ss_prefix="screenshot_";
$ss_suffix=".png";
$ss_digits=4;
$ss_timeout=0.1;
$ss_retries=20;
$pattern="${ss_prefix}[0-9]{$ss_digits}${ss_suffix}";
$npattern="${ss_folder}/${ss_prefix}%0${ss_digits}d${ss_suffix}";
if(opendir(DIR,"${ss_folder}"))
{
    waitforlock($lockfile);
    $file=(reverse sort grep(/$pattern/, readdir DIR))[0];
    if($file=~/([0-9]+)/)
    {
      $no=1+$1;
    } else {
      $no=0;
    }
    $newfile=sprintf($npattern,$no);
    touchfile($newfile);
    system("import -window root ${newfile} &");
}
sub waitforlock
{
    my $handle=shift;
    my $count=0;
    until(sysopen(FH, $lockfile, O_WRONLY|O_CREAT) && flock(FH, LOCK_EX|LOCK_NB))
    {
      sleep $ss_timeout;
      if(++$count > $ss_retries)
      {
          print "Sorry, can't create screenshots right now\n";
          exit;
      }
    }
}
sub touchfile
{
    my $handle=shift;
    open(FILE,">$handle");
    close(FILE);
}
anonymous

Последний перл скрипт от Гения мне сказал sorry.

Последний sh скрипт sas работат нормально, но есть одна проблема скрипт сделан для запуска его из консоли, но в консоли мне не нужно делать скриншоты. Поставал я на кнопочку printscreen запуск этого скрипта, и если кнопку удерживать, то открывается много printscreen и при этом они работают секунд по 20 (под курсором появляются часики и в таскбаре висят — некрасиво).

Как сделать чтобы при зажатии printscreen запускался только один скрипт, а следущий раз он запускался только когда я повторно зажму кнопку и пусть он как только сделал скрин завершал работу, не ждал бы чего, было бы вообще здорово еслибы он в фоне работал, просто на рабочем столе появлялся бы скриншот после нажатия кнопки, без каких либо сообщений о том что работал скрипт.

Genie

1) Перманентно «Sorry…» мой скрипт сказать мог только в том случае, если в /var/lock данный пользователь не может писать. Что, в общем-то, странно, так как /var/lock, /var/run имеют такие же права (по крайней мере в debian), как и /tmp.

Поэтому, если возникает такая проблема — надо просто поменять местоположение этого файла. Да на /tmp/screenshot.lock, к примеру. Или где-то в домашнике.

2) Так же необходимо настроить остальные переменные (к примеру, создать папку ~/screenshots и указать полный путь до неё в переменной $ss_folder. Так же надо настроить и остальное по желанию.

3) Что касается не ожидания, а выхода из скрипта сразу. Участок кода

until(sysopen(FH, $lockfile, O_WRONLY|O_CREAT) && flock(FH, LOCK_EX|LOCK_NB))

{

sleep $ss_timeout;

if(++$count > $ss_retries)

{

print «Sorry, can’t create screenshots right now\n»;

exit;

}

}


заменить на простое

if(!(sysopen(FH, $lockfile, O_WRONLY|O_CREAT) && flock(FH, LOCK_EX|LOCK_NB)))

{

exit;

}

anonymous

Вот на Python`e

printscrn.py ———————————————

#! /usr/bin/env python

import os,sys,pwd

try:

quality = sys.argv[1]

if 0 < int(quality) <= 100:

pass

else:

print «\033[1;31mError:\033[m Quality range > 0 or >= 100"

except:

quality = 90

printdir = "%s/Screen" % pwd.getpwnam(os.environ.get("USER"))[5]

if os.path.exists(printdir):

pass

else:

os.mkdir(printdir)

try:

filelst = os.listdir(printdir)

num = int(len(filelst))

file = «Screen%02d.png» % num

if os.path.exists(«%s/%s» % (printdir,file)):

num = num + 1

file = «Screen%02d.png» % num

except:

file = «Screen%02d.png» % 0

os.system(«import -window root -quality %s %s/%s» % (quality,printdir,file) )

print «ScreenShot copying to [ %s/%s ]» % (printdir,file)

———————————

anonymous

[root@localhost Desktop]# python2.3 printscrn.py

File «printscrn.py», line 8

pass

^

IndentationError: expected an indented block

НЕ работает

anonymous

Там все рыботает !, просто надо правильно поставить отступы !

ecobeingecobeing.ru
Экология и вегетарианство на благо всем живым существам Планеты.