![如何使用 CRONTAB 运行 pynput 和 FFMPEG 脚本?](https://linux22.com/image/932997/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%20CRONTAB%20%E8%BF%90%E8%A1%8C%20pynput%20%E5%92%8C%20FFMPEG%20%E8%84%9A%E6%9C%AC%EF%BC%9F.png)
我需要开始三个 python3 脚本和一个使用 crontab 的 shell 脚本。这些脚本应该同时运行,没有任何延迟。每个脚本运行一分钟。例如,我已安排 crontab 每 5 分钟运行一次这些脚本。
我的问题是,如果我尝试单独运行每个脚本终端它执行时没有进一步的错误,但使用 crontab 什么也不会发生。
这是我的 crontab 设置:
*/5 * * * * cd /home/user/Desktop/ && /usr/bin/python3 script1.py >> report1.log
*/5 * * * * cd /home/user/Desktop/ && /usr/bin/python3 script2.py >> report2.log
*/5 * * * * cd /home/user/Desktop/ && /usr/bin/python3 script3.py >> report3.log
*/5 * * * * cd /home/user/Desktop/ && /usr/bin/sh script4.sh >> report4.log
另外我需要提一下,shell脚本包含这个命令(FFMPEG):
#!/bin/bash
parent_dir=`dirname \`pwd\``
folder_name="/Data/Webcam"
new_path=$parent_dir$folder_name
if [ -d "$new_path" ]; then
echo "video_audio folder exists..."
else
echo "Creating video_audio folder in the current directory..."
mkdir -p -- "$new_path"
sudo chmod 777 "$new_path"
echo "Folder created"
echo
fi
now=$(date +%F)
now="$( echo -e "$now" | tr '-' '_' )"
sub_dir=$new_path'/'$now
if [ -d "$sub_dir" ]; then
echo "Date Sub-directory exists..."
echo
else
echo "Error: ${sub_dir} not found..."
echo "Creating date sub-directory..."
mkdir -p -- "$sub_dir"
sudo chmod 777 "$sub_dir"
echo "Date sub-directory created..."
echo
fi
fname=$(date +%H_%M_%S)".avi"
video_dir=$sub_dir'/'$fname
ffmpeg -f pulse -ac 1 -i default -f v4l2 -i /dev/video0 -vcodec libx264 -t 00:01:00 $video_dir
该脚本的日志文件包含以下内容:
video_audio folder exists...
Date Sub-directory exists...
Package ffmpeg is already installed...
Package v4l-utils is already installed...
Package: ffmpeg
Status: install ok installed
Priority: optional
Section: video
Installed-Size: 2010
Maintainer: Ubuntu Developers <[email protected]>
Architecture: amd64
Multi-Arch: foreign
Version: 7:4.2.4-1ubuntu0.1
Replaces: libav-tools (<< 6:12~~), qt-faststart (<< 7:2.7.1-3~)
Depends: libavcodec58 (= 7:4.2.4-1ubuntu0.1), libavdevice58 (= 7:4.2.4-1ubuntu0.1), libavfilter7 (= 7:4.2.4-1ubuntu0.1), libavformat58 (= 7:4.2.4-1ubuntu0.1), libavresample4 (= 7:4.2.4-1ubuntu0.1), libavutil56 (= 7:4.2.4-1ubuntu0.1), libc6 (>= 2.29), libpostproc55 (= 7:4.2.4-1ubuntu0.1), libsdl2-2.0-0 (>= 2.0.10), libswresample3 (= 7:4.2.4-1ubuntu0.1), libswscale5 (= 7:4.2.4-1ubuntu0.1)
Suggests: ffmpeg-doc
Breaks: libav-tools (<< 6:12~~), qt-faststart (<< 7:2.7.1-3~), winff (<< 1.5.5-5~)
Description: Tools for transcoding, streaming and playing of multimedia files
FFmpeg is the leading multimedia framework, able to decode, encode, transcode,
mux, demux, stream, filter and play pretty much anything that humans and
machines have created. It supports the most obscure ancient formats up to the
cutting edge.
.
This package contains:
* ffmpeg: a command line tool to convert multimedia files between formats
* ffplay: a simple media player based on SDL and the FFmpeg libraries
* ffprobe: a simple multimedia stream analyzer
* qt-faststart: a utility to rearrange Quicktime files
Homepage: https://ffmpeg.org/
Original-Maintainer: Debian Multimedia Maintainers <[email protected]>
Package: v4l-utils
Status: install ok installed
Priority: optional
Section: utils
Installed-Size: 2104
Maintainer: Ubuntu Developers <[email protected]>
Architecture: amd64
Version: 1.18.0-2build1
Replaces: ivtv-utils (<< 1.4.1-2), media-ctl
Depends: libv4l-0 (= 1.18.0-2build1), libv4l2rds0 (= 1.18.0-2build1), libc6 (>= 2.17), libgcc-s1 (>= 3.0), libstdc++6 (>= 5.2), libudev1 (>= 183)
Breaks: ivtv-utils (<< 1.4.1-2), media-ctl
Description: Collection of command line video4linux utilities
v4l-utils contains the following video4linux command line utilities:
.
decode_tm6000: decodes tm6000 proprietary format streams
rds-ctl: tool to receive and decode Radio Data System (RDS) streams
v4l2-compliance: tool to test v4l2 API compliance of drivers
v4l2-ctl, cx18-ctl, ivtv-ctl: tools to control v4l2 controls from the cmdline
v4l2-dbg: tool to directly get and set registers of v4l2 devices
v4l2-sysfs-path: sysfs helper tool
Original-Maintainer: Gregor Jasny <[email protected]>
Homepage: https://linuxtv.org/downloads/v4l-utils/
由于 python 文件具有相同的结构,因此我在此上传了一个示例文件:
# -*- coding: utf-8 -*-
from threading import Timer
from pynput.mouse import Listener
import logging
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(
os.path.realpath(__file__)), "../"))
from Functions import utils as ut
if __name__=='__main__':
ut.initialize_dirs()
rec_file = ''.join(('mouse_',ut.get_date(),'.txt'))
raw_data = ut.get_name('Mouse')
rec_file = os.path.join(raw_data,rec_file)
logging.basicConfig(filename=rec_file,level=logging.DEBUG,format="%(asctime)s %(message)s")
try:
with Listener(on_move=ut.on_move, on_click=ut.on_click,on_scroll=ut.on_scroll) as listener:
Timer(60, listener.stop).start()
listener.join()
except KeyboardInterrupt as err:
print(err)
sys.exit(0)
print('Exiting logger...')
我还上传了我使用的功能:
# -*- coding: utf-8 -*-
from serial import Serial
from datetime import datetime, timedelta
import pandas as pd
import collections
import logging
import shutil
import serial
import time
import sys
import os
click_held = False
button = None
def on_move(x,y):
"""The callback to call when mouse move events occur
Args:
x (float): The new pointer position
y (float): The new pointer poisition
"""
if click_held:
logging.info("MV {0:>8} {1:>8} {2:>8}:".format(x,y,str(None)))
else:
logging.info("MV {0:>8} {1:>8} {2:>8}:".format(x,y,str(None)))
def on_click(x,y,button,pressed):
"""The callback to call when a mouse button is clicked
Args:
x (float): Mouse coordinates on screen
y (float): Mouse coordinates on screen
button (str): one of the Button values
pressed (bool): Pressed is whether the button was pressed
"""
global click_held
if pressed:
click_held = True
logging.info("CLK {0:>7} {1:>6} {2:>13}".format(x,y,button))
else:
click_held = False
logging.info("RLS {0:>7} {1:>6} {2:>13}".format(x,y,button))
def on_scroll(x,y,dx,dy):
"""The callback to call when mouse scroll events occur
Args:
x (float): The new pointer position on screen
y (float): The new pointer position on screen
dx (int): The horizontal scroll. The units of scrolling is undefined
dy (int): The vertical scroll. The units of scrolling is undefined
"""
if dy == -1:
logging.info("SCRD {0:>6} {1:>6} {2:>6}".format(x,y,str(None)))
elif dy == 1:
logging.info("SCRU {0:>6} {1:>6} {2:>6}".format(x,y,str(None)))
else:
pass
def on_press_keys(key):
"""The callback to call when a button is pressed.
Args:
key (str): A KeyCode,a Key or None if the key is unknown
"""
subkeys = [
'Key.alt','Key.alt_gr','Key.alt_r','Key.backspace',
'Key.space','Key.ctrl','Key.ctrl_r','Key.down',
'Key.up','Key.left','Key.right','Key.page_down',
'Key.page_up','Key.enter','Key.shift','Key.shift_r'
]
key = str(key).strip('\'')
if(key in subkeys):
#print(key)
logging.info(key)
else:
pass
def record_chair(output_file):
"""Read the data stream coming from the serial monitor
in order to get the sensor readings
Args:
output_file (str): The file name, where the data stream will be stored
"""
serial_port = "/dev/ttyACM0"
baud_rate = 9600
ser = serial.Serial(serial_port,baud_rate)
logging.basicConfig(filename=output_file,level=logging.DEBUG,format="%(asctime)s %(message)s")
flag = False
start = time.time()
while time.time() - start < 60.0:
try:
serial_data = str(ser.readline().decode().strip('\r\n'))
time.sleep(0.2)
tmp = serial_data.split(' ')[0] #Getting Sensor Id
if(tmp == 'A0'):
flag = True
if (flag and tmp != 'A4'):
#print(serial_data)
logging.info(serial_data)
if(flag and tmp == 'A4'):
flag = False
#print(serial_data)
logging.info(serial_data)
except (UnicodeDecodeError, KeyboardInterrupt) as err:
print(err)
print(err.args)
sys.exit(0)
def initialize_dirs():
"""Create the appropriate directories in order to save
and process the collected data
"""
current_path = os.path.abspath(os.getcwd())
os.chdir('..')
current_path = (os.path.abspath(os.curdir)) #/Multodal_User_Monitoring
current_path = os.path.join(current_path,'Data')
create_subdirs([current_path])
#Create mouse log folder
mouse = os.path.join(current_path,'Mouse')
create_subdirs([mouse])
#Create mouse subfolders
names = concat_names(mouse)
create_subdirs(names)
#Create keyboard log folder
keyboard = os.path.join(current_path,'Keyboard')
create_subdirs([keyboard])
#Create keyboard subfolders
names = concat_names(keyboard)
create_subdirs(names)
#Create the chair log folder
chair = os.path.join(current_path,'Chair')
create_subdirs([chair])
#Create chair subfolders
names = concat_names(chair)
create_subdirs(names)
#Create webcam log folder
webcam = os.path.join(current_path,'Webcam')
create_subdirs([webcam])
def concat_names(dir) -> str:
"""Concatenate the given folder names
with the appropriate path
Args:
dir (str): The directory to create the subfolders
Returns:
list: The new absolute paths
"""
raw_data = os.path.join(dir,'Raw')
edited_data = os.path.join(dir,'Edited_logs')
csv_data = os.path.join(dir,'CSV')
features = os.path.join(dir,'Features')
dirs = [raw_data,edited_data,csv_data,features]
return dirs
def create_subdirs(paths):
"""Create sub directories given some absolute paths
Args:
paths (list): A list containing the paths to be created
"""
for index,path in enumerate(paths):
if(os.path.isdir(paths[index])):
pass
else:
os.mkdir(paths[index])
def round_down(num,divisor) -> int:
"""Round the number of lines contained into the recording file,
down to the nearest multiple of the given divisor
Args:
num (int): The number of lines contained into the given log file
divisor (int): The divisor in order to get tuples of divisor
Returns:
int: The nearest multiple of five
"""
return num-(num%divisor)
def get_date() -> str:
"""Get the current date in order to properly name
the recored log files
Returns:
str: The current date in: YY_MM_DD format
"""
return datetime.now().strftime('%Y_%m_%d')
def get_name(modality) -> str:
"""Save the recorded log into /Data/<Modality_name>/Raw
Args:
modality (str): The log data source
Returns:
str: The absolute path where each recording is saved
"""
current_path = os.path.abspath(os.getcwd())
current_path = os.path.join(current_path,'Data')
if modality == 'Chair':
chair_path = os.path.join(current_path,modality,'Raw')
return chair_path
elif modality == 'Mouse':
mouse_path = os.path.join(current_path,modality,'Raw')
return mouse_path
elif modality == 'Keyboard':
keyboard_path = os.path.join(current_path,modality,'Raw')
return keyboard_path
def crawl_dir(target,folder) -> str:
"""Enumerate all the given files in a directory
based on the given file extension
Args:
target (str): The file to search for
folder (str): The folder to search
Returns:
[type]: A list containing the file names
"""
current_path = os.path.abspath(os.getcwd())
path = os.path.join(current_path,folder)
file_names =[]
for f in os.listdir(path):
if(f.endswith(target)):
fname=os.path.join(path,f)
file_names.append(fname)
return file_names
def convert_keys2_csv(input_file,output_file):
"""Convert the data stream file(keylogger recording) from .txt to .csv format
Args:
input_file (str): The data stream file in .txt format
output_file (str): The csv extension file name
"""
df = pd.read_fwf(input_file)
col_names = ['Date','Time','Key']
df.to_csv(output_file,header=col_names,encoding='utf-8',index=False)
def convert_mouse2_csv(input_file,output_file):
"""Convert the data stream file(mouselogger recording) from .txt to .csv format
Args:
input_file (str): The data stream file in .txt format
output_file (str): The csv extension file name
"""
df = pd.read_fwf(input_file)
col_names = ['Date','Time','Action','PosX','PosY','Button']
df.to_csv(output_file,header=col_names,encoding='utf-8',index=False)
def convert_chair_2_csv(input_file,output_file):
"""Convert the data stream file(chair recording)
from .txt to .csv format
Args:
input_file (str): The data stream file in .txt format
output_file (str): The csv extension file name
"""
if(os.path.isfile(input_file)):
pass
else:
print('Invalid working directory...')
print('Aborting...')
sys.exit(0)
tmp0,tmp1,tmp2,tmp3,tmp4 = 0,1,2,3,4
line_number = 0
for line in open(input_file).readlines():
line_number += 1
rounded_line = round_down(line_number,5)
d = collections.defaultdict(list)
with open(input_file,'r') as f1:
lines = f1.readlines()
for i in range(rounded_line // 5):
#Sensor:Analog input 0 values
Sid0 = lines[i+tmp0]
temp = Sid0.split()
d['Sid0'].append([temp[0],temp[1],temp[2],temp[3]])
#Sensor:Analog input 1 values
Sid1 = lines[i+tmp1]
temp = Sid1.split()
d['Sid1'].append([temp[0],temp[1],temp[2],temp[3]])
#Sensor:Analog input 2 values
Sid2 = lines[i+tmp2]
temp = Sid2.split()
d['Sid2'].append([temp[0],temp[1],temp[2],temp[3]])
#Sensor:Analog input 3 values
Sid3 = lines[i+tmp3]
temp = Sid3.split()
d['Sid3'].append([temp[0],temp[1],temp[2],temp[3]])
#Sensor:Analog input 4 values
Sid4 = lines[i+tmp4]
temp = Sid4.split()
d['Sid4'].append([temp[0],temp[1],temp[2],temp[3]])
tmp0 += 4
tmp1 += 4
tmp2 += 4
tmp3 += 4
tmp4 += 4
l = []
for i in range(rounded_line // 5):
date = d['Sid0'][i][0]
time = d['Sid0'][i][1]
A0_val = d['Sid0'][i][3]
A1_val = d['Sid1'][i][3]
A2_val = d['Sid2'][i][3]
A3_val = d['Sid3'][i][3]
A4_val = d['Sid4'][i][3]
l.append([date,time,A0_val,A1_val,A2_val,A3_val,A4_val])
sensor_readings_df = pd.DataFrame.from_records(l)
sensor_readings_df.columns = ['Date','Time','A0','A1','A2','A3','A4']
sensor_readings_df.to_csv(output_file, encoding='utf-8', index=False)
del l
def parse_raw_data(modality):
"""Convert each modality's raw data into csv format and move
the edited raw data into the appropriate Edited_logs folder
Args:
modality (str): The data source
"""
#Change directories
current_path = os.path.abspath(os.getcwd()) #/Functions
os.chdir('..')
current_path = (os.path.abspath(os.curdir)) #/Multimodal_User_Monitoring
os.chdir('./Data')#/Multimodal_User_Monitoring/Data
current_path = (os.path.abspath(os.curdir)) #/Multimodal_User_Monitoring/Data
current_path = os.path.join(current_path,modality) #example: /Multimodal_User_Monitoring/Data/<Modality>
raw_data_path = os.path.join(current_path,'Raw')
csv_data_path = os.path.join(current_path,'CSV')
edited_logs_path = os.path.join(current_path,'Edited_logs')
txt_names = crawl_dir('.txt',raw_data_path)
csv_names = []
for elem in txt_names:
name = elem.split('/')[-1].split('.')[0]
csv_name = name+'.csv'
tmp = os.path.join(csv_data_path,csv_name)
csv_names.append(tmp)
if modality == 'Mouse':
if len(txt_names) == len(csv_names):
for i, elem in enumerate(txt_names):
#for i in range(len(txt_names)):
convert_mouse2_csv(txt_names[i],csv_names[i])
shutil.move(txt_names[i],edited_logs_path)
elif modality == 'Keyboard':
if len(txt_names) == len(csv_names):
for i, elem in enumerate(txt_names):
#for i in range(len(txt_names)):
convert_keys2_csv(txt_names[i],csv_names[i])
shutil.move(txt_names[i],edited_logs_path)
elif modality == 'Chair':
if len(txt_names) == len(csv_names):
for i, elem in enumerate(txt_names):
#for i in range(len(txt_names)):
convert_chair_2_csv(txt_names[i],csv_names[i])
shutil.move(txt_names[i],edited_logs_path)
需要指出的是,python3 脚本的日志是空的