#!/bin/bash # Statistics of camera RAW images with GNU Plot & Exiftool # Copyright (C) 2017 Pekka Helenius # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # ############################################### # TODO list: # TODO Add message, either of these: # If not a geotagged image file: # A You haven't geotagged selected photos. Are you sure you want to continue? # B Following photos don't have altitude value: XX XX XX Are you sure you want to continue? # TODO IF INPUT IS A CSV FILE, DO NOT SUGGEST 'EXPORT ONLY' AS AN OPTION # TODO if user chooses alternative 'Export CSV' only, do not crash if errtags or errnames encountered # # TODO Be more specific in which case errtags may crash the operation. For instance, if user has chosen only Temperature and ISO to be plotted on GNU Plot, do not crash in case where Focal Length is missing. In other words: be more specific in which conditions match the crash requirement, do not crash the process for nothing. # TODO The script has only been tested on Canon 5D Mark 3 CR2 files. How does the script work with other Canon camera models? And what about Sony, Nikon? # # TODO Re-write, parse and simplify some scripts logics! ############################################### # Supported & tested camera raw pictures: # Canon EOS 5D Mark 3 # TOOL REQUIREMENTS # perl-exiftool # kdialog (Qt5) # qt5-tools (qdbus) # coreutils (md5sum, echo etc..) # netpbm (pgmhist) # dcraw # gawk # gnuplot (+ Qt interface) # # # OTHER REQUIREMENTS # # Recommended: Qt5 Dolphin file manager (dolphin) # # This script is meant to be run as a Dolphin File Manager script (Qt5). It gets file arguments straight from Dolphin # You can run the script in bash (or execute Dolphin via bash) to get detailed script output (CLI messages, debug messages etc.) # #BRACKETS AND QUOTATION MARKS ARE USED IN THIS SCRIPT BECAUSE FOLDER AND FILE PATHS MAY CONTAIN SPACES! ####################################################################### # VARIABLES FOR THE SCRIPT CSV_FILECOUNT=$(printf '%s\n' "${@}" | rev | cut -f 1 -d '.' | rev | grep -i "csv" | wc -l) RAW_FILECOUNT=$(printf '%s\n' "${@}" | rev | cut -f 1 -d '.' | rev | grep -i -E "cr2|nef|dng" | wc -l) COLUMNCOUNT=24 #Count of all columns must be found in CSV file. This number must match with the number found in kdialog processing dialog below. ####################################################################### # 1ST FILE CHECK if [[ "${@}" == "" ]]; then kdialog --error "Not any files selected!"; exit elif [[ ! $CSV_FILECOUNT == 0 ]] && [[ ! $RAW_FILECOUNT == 0 ]]; then kdialog --error "Select only RAW files or a single CSV file!"; exit elif [[ $CSV_FILECOUNT -gt 1 ]]; then kdialog --error "Select only one CSV file!"; exit elif [[ $RAW_FILECOUNT == 1 ]]; then kdialog --error "Please select at least 2 valid RAW files or a CSV file!"; exit elif [[ $RAW_FILECOUNT == 0 ]] && [[ $CSV_FILECOUNT == 0 ]]; then kdialog --error "Please select valid RAW files or a CSV file!"; exit fi ####################################################################### # KDIALOG CHECK LIST FORMATTED SELECTION WINDOW if [[ $RAW_FILECOUNT == 0 ]] && [[ $CSV_FILECOUNT == 1 ]]; then SELECTION=$(kdialog --checklist "Select statistics to display:" \ 1 "" off \ 2 "" off \ 3 "Temperatures & ISOs" on \ 4 "" off \ ); # 1 Apertures, Exposures & ISOs # 2 Focal Lengths & Lenses # 3 Temperatures & ISOs # 4 Shooting & Focus Modes if [ "$?" = 0 ]; then if [ $(expr length "$SELECTION") != 0 ]; then for result in $SELECTION do if [ $result = '"1"' ]; then SEL1=true fi if [ $result = '"2"' ]; then SEL2=true fi if [ $result = '"3"' ]; then SEL3=true fi if [ $result = '"4"' ]; then SEL4=true fi done else kdialog --sorry "Aborted"; fi elif [ "$?" = 1 ]; then exit 0 else kdialog --error "Unexpected Error"; fi SEL5=false fi if [[ $RAW_FILECOUNT != 0 ]] && [[ $CSV_FILECOUNT == 0 ]]; then SELECTION=$(kdialog --checklist "Select statistics to display:" \ 1 "" off \ 2 "" off \ 3 "Temperatures & ISOs" on \ 4 "" off \ 5 "Export Only (CSV)" off \ ); # 1 Apertures, Exposures & ISOs # 2 Focal Lengths & Lenses # 3 Temperatures & ISOs # 4 Shooting & Focus Modes # 5 Export Only (CSV) if [ "$?" = 0 ]; then if [ $(expr length "$SELECTION") != 0 ]; then for result in $SELECTION do if [ $result = '"1"' ]; then SEL1=true fi if [ $result = '"2"' ]; then SEL2=true fi if [ $result = '"3"' ]; then SEL3=true fi if [ $result = '"4"' ]; then SEL4=true fi if [ $result = '"5"' ]; then #If checked, we force all other values to be false SEL5=true SEL4=false SEL3=false SEL2=false SEL1=false fi done else kdialog --sorry "Aborted"; fi elif [ "$?" = 1 ]; then exit 0 else kdialog --error "Unexpected Error"; fi fi # SEL1 = "Apertures, Exposures & ISOs" true/false # SEL2 = "Focal Lengths & Lenses" true/false # SEL3 = "Temperatures & ISOs" true/false # SEL4 = "Shooting & Focus Modes" true/false # SEL5 = "Export Only (CSV)" true/false ####################################################################### #We get the directory just from the first filename. Pwd should be easier, but bugged, so... INPUT_DIR=$(dirname "${1}") DIR_BASENAME=$(echo -n "${INPUT_DIR}" | rev | cut -d'/' -f 1 | rev) #First & Last file names (without suffixes) for last; do true; done FIRST=$(basename "${1}" | cut -f 1 -d '.') #Name of the first file passed into the script LAST=$(basename "${last}" | cut -f 1 -d '.') #Name of the last file passed into the script #File name is based on the folder where files exist FILENAME=$(echo "${DIR_BASENAME}-${FIRST}-${LAST}_metadata") FILE_EXT=.csv #Sed is here to remove any trailing spaces and crap like blank lines INPUT_FILESYSTEM=$(df -h "${1}" | awk -F ' ' 'FNR> 1 {print $1}' | grep -i -E "/dev/sd?|/dev/hd?|?rewritefs|/dev/nvme?" | sed '/^\s*$/d' | wc -l) ####################################################################### # 2ND FILE CHECK # Check if we are dealing with a CSV file or bunch of RAW files. if [[ $CSV_FILECOUNT == 1 ]]; then FILENAME=$(basename "${1}" | sed 's/\.\w*$//') #without a suffix. #We use valid existing CSV file name here CSVFOLDER="${INPUT_DIR}" #We don't need to redirect this folder path to $HOME because we assume this file already exists # If the first input file is not CSV but a RAW file, then we check the filesystem of this file and decide whether to use $HOME folder or picture folder for a new CSV file. # We don't need this check for any CSV files, because we just extract information from them, not any write operations are required. elif [[ $RAW_FILECOUNT != 0 ]]; then echo "Multiple RAW files." if [[ "${INPUT_FILESYSTEM}" -eq 0 ]]; then #if input file (first file printed in bash) filesystem does not start with /dev/sdX CSVFOLDER="${HOME}" kdialog --msgbox "Images are in a SD Card. Writing EXIF CSV data file to ${HOME}/" # TODO If we have exactly same files selected in SD card but we don't have CSV file in home folder, this doesn't work as expected. It assumes the file to be checked is in home folder. else CSVFOLDER="${INPUT_DIR}" fi fi RAWDATA_TMP="${CSVFOLDER}/${FILENAME}${FILE_EXT}" ####################################################################### # 1) CHECK CSV FILE VALIDITY AGAINST THE SCRIPT OUTPUT # 2) GET VALUE FOR 'INPUT_FILES_MD5SUM' VARIABLE # NOTE: We don't check MD5Sums, if we use CSV file as an input. Though this file can exist in the same folder with the pictures, we want to keep CSV files as portable as possible in general. # Thus, we don't do the following check: CSV file list MD5Sums vs actual corresponding files in the folder (if only CSV is selected as input). This can arise other problems such as images # with equivalent names listed in CSV file but they are actually different files. This causes mismatch between CSV file content and folder content. So, no go. # 1) Check validity of the selected CSV file for analysis purposes. Not RAW files selected. if [[ -e "${RAWDATA_TMP}" ]]; then # Referring to existing CSV file here. User input may or may not be a CSV file, so we don't check it. echo "This is a valid CSV file. Checking columns." FILE_COLUMNCOUNT=$(echo -n $(awk -F ',' '{print NF}' "${RAWDATA_TMP}" | sort -nu)) #This *must* return only one value (equal to COLUMNCOUNT). If many values are returned CSV file can't be used because, therefore, there are mismatch between column numbers in rows. FILE_HASMD5COLUMN=$(awk -F ',' '{print $2}' "${RAWDATA_TMP}" | head -n 1) FILE_MD5_CHARNUM=$(echo -n $(awk -F ',' ' FNR > 1 {print length($2)}' "${RAWDATA_TMP}" | sort -nu)) #This *must* return only one value. Value 32. # If the input csv file has valid count of columns and the second column includes md5sums. if [[ $FILE_COLUMNCOUNT -eq $COLUMNCOUNT ]] && [[ $FILE_HASMD5COLUMN == "File MD5Sum" ]] && [[ $FILE_MD5_CHARNUM == 32 ]]; then COLUMNS_OK=true echo "Columns OK, continuing." elif [[ $RAW_FILECOUNT == 0 ]]; then echo -e "Charnum is:$FILE_MD5_CHARNUM" echo "Error in columns." kdialog --error "Error in CSV file columns!"; exit else echo "Error in matching file columns. RAW files as input." COLUMNS_OK=false #This is a case where we have detected a pattern matcing CSV file but it has invalid columns. fi fi # 2) Instead of single CSV file, if multiple RAW files have been selected, then if [[ $RAW_FILECOUNT != 0 ]]; then echo "Getting MD5Sums for RAW files..." #get md5sums for the files and print output #Syntax: IMG_8217,IMG_8408,IMG_8544 ... (replace these file names just with md5sums and you get the idea) INPUT_FILES_MD5SUM=$(echo -n $(printf '%s\n' $(md5sum "${@}") | sed '$!N;s/\n/ /' | awk -F ' ' '{print $2,$1}' | sed -e 's/^.*\///' | sort -n | awk -F ' ' '{print $2}' | tr '\n' ',' | sed 's/,*\r*$//')) echo "Comparing MD5Sums..." MAINCSV=$(find "${CSVFOLDER}" -maxdepth 1 -iname "${FILENAME}*${FILE_EXT}") MAINCSV_COUNT=$(find "${CSVFOLDER}" -maxdepth 1 -iname "${FILENAME}*${FILE_EXT}" | wc -l) OTHER_CSV=$(find "${CSVFOLDER}" -maxdepth 1 -iname "*${FILE_EXT}") OTHER_CSV_COUNT=$(find "${CSVFOLDER}" -maxdepth 1 -iname "*${FILE_EXT}" | wc -l) # Main CSV file if [[ $COLUMNS_OK == true ]]; then COMPAREFILE_MD5SUM=$(echo -n $(awk -F ',' 'FNR> 1 {print $1,$2}' "${RAWDATA_TMP}" |sort -n | awk -F ' ' '{print $2}' | tr '\n' ',' | sed 's/,*\r*$//')) #if md5sums match OK, then... if [[ "$INPUT_FILES_MD5SUM" == "$COMPAREFILE_MD5SUM" ]]; then echo -e "MD5Sums match OK." USEMAINCSV=true else echo -e "MD5Sums match not OK." USEMAINCSV=false fi fi # Other CSV files, including variant of the CSV "file template" if [[ ! -e "${RAWDATA_TMP}" ]] || [[ ! $OTHER_CSV_COUNT == 0 ]] || [[ $USEMAINCSV == false ]]; then # Check for CSV variants (which match the filename syntax) if [[ $MAINCSV_COUNT -gt 0 ]]; then for m in $MAINCSV; do echo "DEBUG: Do we get here 1?" COMPAREFILE_MD5SUM=$(echo -n $(awk -F ',' 'FNR> 1 {print $1,$2}' "${m}" |sort -n | awk -F ' ' '{print $2}' | tr '\n' ',' | sed 's/,*\r*$//')) if [[ "$INPUT_FILES_MD5SUM" == "$COMPAREFILE_MD5SUM" ]]; then RAWDATA_TMP="${m}" FILENAME=$(basename "${m}" | cut -f 1 -d '.') #We get the existing file name template and remove extension. echo "DEBUG: Do we get here 2?" USEMAINCSV=true break else echo "DEBUG: Do we get here 3?" USEMAINCSV=false fi done fi # Check for other CSVs if [[ $MAINCSV_COUNT -eq 0 ]] || [[ ! $OTHER_CSV_COUNT == 0 ]] && [[ $USEMAINCSV == false ]]; then for f in $OTHER_CSV; do echo "DEBUG: Do we get here 4?" COMPAREFILE_MD5SUM=$(echo -n $(awk -F ',' 'FNR> 1 {print $1,$2}' "${f}" |sort -n | awk -F ' ' '{print $2}' | tr '\n' ',' | sed 's/,*\r*$//')) if [[ "$INPUT_FILES_MD5SUM" == "$COMPAREFILE_MD5SUM" ]]; then RAWDATA_TMP="${f}" FILENAME=$(basename "${f}" | cut -f 1 -d '.') #We get the existing file name template and remove extension. echo "DEBUG: Do we get here 5?" USEOTHERCSV=true break else echo "DEBUG: Do we get here 6?" USEOTHERCSV=false fi done fi fi fi if [[ $USEMAINCSV == false ]] && [[ $USEOTHERCSV == false ]]; then echo "DEBUG: Do we get here 7?" x=1 while [[ -e "${CSVFOLDER}/${FILENAME}-${x}${FILE_EXT}" ]]; do let x++ done FILENAME="${FILENAME}-${x}" fi echo -e "MD5Sums checked.\n" if [[ $USEMAINCSV == true ]] || [[ $USEOTHERCSV == true ]]; then echo -e "Found an existing CSV file with MD5Sums.\n" elif [[ $USEMAINCSV == true ]] && [[ $USEOTHERCSV == false ]]; then echo -e "Using existing CSV with correct file template.\n" elif [[ $USEMAINCSV == true ]] && [[ $USEOTHERCSV == false ]]; then echo -e "Using a custom named CSV file.\n" elif [[ $USEMAINCSV == false ]] || [[ $USEOTHERCSV == false ]]; then echo -e "Creating a new CSV file.\n" fi ####################################################################### #We need to redefine bash variables to overwrite the old values! FILENAME2="${FILENAME}-temp" FILENAME3="${FILENAME}-iso" RAWDATA_TMP="${CSVFOLDER}/${FILENAME}${FILE_EXT}" RAWDATA_TMP2="/tmp/${FILENAME2}${FILE_EXT}" RAWDATA_TMP3="/tmp/${FILENAME3}${FILE_EXT}" ################# #DEBUGGING echo "We use file named $RAWDATA_TMP" if [[ $SEL3 == true ]]; then echo "We use isofile named $RAWDATA_TMP2" echo "We use tempfile named $RAWDATA_TMP3" fi #echo #exit ################# ############################################################################################################################################## # KDIALOG PROCESSING WINDOW - BEGIN ####PROGRESSBAR STUFF - BEGIN LABELTEXT='Exporting statistics...' numargs=$# # Number of all files tics=100 # Percentage tics inc=0 # Current file number mltp=1000 # Percentage multiplier for bash if [[ ! -e "${RAWDATA_TMP}" ]]; then #If the file already exists, we don't want overwrite it. Instead, we skip these steps to speed up the process. dbusRef=$(kdialog --title "Metadata Extraction ($DIR_BASENAME: images $FIRST-$LAST)" --progressbar "$LABELTEXT" $tics) qdbus $dbusRef showCancelButton true ####PROGRESSBAR STUFF - END while [[ $# -gt 0 ]] && [[ $(qdbus $dbusRef wasCancelled) == "false" ]]; do i="${1}" ############################################## # 1 COLUMN # ENABLE THIS IF STATEMENT ONLY IF FILE NAMES CONTAINING 'IMG_' ARE ONLY ACCEPTED #if [[ ! $(echo $(basename "${1}" | cut -f 1 -d '.')) == *"IMG_"* ]]; then # echo $(basename "${1}" | cut -f 1 -d '.') # ERRFILE=1 #PRINT INVALID INPUT AS THE LAST COLUMN DUE TO DATE/TIME COLUMNS! SEE BELOW! #else echo $(basename "${i}" | cut -f 1 -d '.') #| sed -e 's/IMG_//g') #echo ${i##*/} | sed -e 's/.CR2//g' -e 's/.DNG//g') # ERRFILE=0 #fi ############################################## # 2 COLUMN #Write md5sum of a file for checking purposes! md5sum "${i}" | awk -F ' ' '{print $1}' ############################################## # 3 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Camera Temperature" | sed -e 's/[^0-9]*//g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Camera Temperature" | sed -e 's/[^0-9]*//g' else echo "errtag" fi ############################################## # 4 COLUMN # ISO Speed setting (yeah, we get it from "Recommended Exposure Index" tag. if [[ $(exiftool "${i}" | grep -v "Sensitivity" | grep --max-count=1 "Recommended Exposure Index" | sed 's/[^0-9]*//g' | wc -l) -eq 1 ]]; then exiftool "${i}" | grep -v "Sensitivity" | grep --max-count=1 "Recommended Exposure Index" | sed 's/[^0-9]*//g' else echo "errtag" fi ############################################## # 5 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Exposure Time" | sed -e 's/[A-Za-z]*//g' -e 's/.*: //g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Exposure Time" | sed -e 's/[A-Za-z]*//g' -e 's/.*: //g' else echo "errtag" fi ############################################## # 6 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Target Exposure Time" | sed -e 's/[A-Za-z]*//g' -e 's/.*: //g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Target Exposure Time" | sed -e 's/[A-Za-z]*//g' -e 's/.*: //g' else echo "errtag" fi ############################################## # 7 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Exposure Compensation" | sed -e 's/[A-Za-z]*//g' -e 's/.*: //g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Exposure Compensation" | sed -e 's/[A-Za-z]*//g' -e 's/.*: //g' else echo "errtag" fi ############################################## # 8 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Aperture Value" | sed -e 's/[A-Za-z]*//g' -e 's/.*: //g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Aperture Value" | sed -e 's/[A-Za-z]*//g' -e 's/.*: //g' else echo "errtag" fi ############################################## # 9 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Target Aperture" | sed -e 's/[A-Za-z]*//g' -e 's/.*: //g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Target Aperture" | sed -e 's/[A-Za-z]*//g' -e 's/.*: //g' else echo "errtag" fi ############################################## # 10 COLUMN # Average histogram value for image (brightness etc.) # For documentation, see http://netpbm.sourceforge.net/doc/pgmhist.html # we need to convert the image into grayscale with dcraw -d option # dcraw "manual" is found here: http://www.inweb.ch/foto/dcrawhelp.txt if [[ $(dcraw -d -4 -j -c "${i}" | pgmhist -median | wc -l) -eq 1 ]]; then dcraw -d -4 -j -c "${i}" | pgmhist -median | sed 's/[^0-9]*//g' else echo "errtag" fi ############################################## # 11 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Focal Length" | sed -e 's/[A-Za-z]*//g' -e 's/.*: //g' -e 's/ //g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Focal Length" | sed -e 's/[A-Za-z]*//g' -e 's/.*: //g' -e 's/ //g' #sed 's/ mm//g' else echo "errtag" fi ############################################## # 12 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Hyperfocal Distance" | sed -e 's/.*: //g' -e 's/ m//g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Hyperfocal Distance" | sed -e 's/.*: //g' -e 's/ m//g' else echo "errtag" fi ############################################## # 13 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Focus Distance Upper" | sed -e 's/.*: //g' -e 's/ m//g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Focus Distance Upper" | sed -e 's/.*: //g' -e 's/ m//g' else echo "errtag" fi ############################################## # 14 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Focus Distance Lower" | sed -e 's/.*: //g' -e 's/ m//g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Focus Distance Lower" | sed -e 's/.*: //g' -e 's/ m//g' else echo "errtag" fi ############################################## # 15 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Depth Of Field" | sed -e 's/.*: //g' -e 's/ m//g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Depth Of Field" | sed -e 's/.*: //g' -e 's/ m//g' else echo "errtag" fi ############################################## # 16 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Camera Model Name" | sed 's/.*: //g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Camera Model Name" | sed 's/.*: //g' else echo "errtag" fi ############################################## # 17 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Lens Type" | sed 's/.*: //g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Lens Type" | sed 's/.*: //g' else echo "errtag" fi ############################################## # 18 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Focus Mode" | sed 's/.*: //g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Focus Mode" | sed 's/.*: //g' else echo "errtag" fi ############################################## # 19 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Shooting Mode" | sed 's/.*: //g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Shooting Mode" | sed 's/.*: //g' else echo "errtag" fi ############################################## # 20 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Live View Shooting" | sed 's/.*: //g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Live View Shooting" | sed 's/.*: //g' else echo "errtag" fi ############################################## # 21 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Camera Orientation" | sed 's/.*: //g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Camera Orientation" | sed 's/.*: //g' else echo "errtag" fi ############################################## # 21 COLUMN # Subject Tags if [ $(exiftool "${i}" |grep --max-count=1 "Subject" | sed -e 's/.*: //g' | wc -l) == 0 ]; then # If Subject tag is empty, get input file filetype (CR2 or cr2 // DNG or dng) if [[ $(echo $(basename "${i}" | cut -f 2 -d '.' | sed '/^\s*$/d')) == "CR2" ]] || [[ $(echo $(basename "${i}" | cut -f 2 -d '.' | sed '/^\s*$/d')) == "cr2" ]]; then echo "Single ISO CR2" elif [[ $(echo $(basename "${i}" | cut -f 2 -d '.' | sed '/^\s*$/d')) == "DNG" ]] || [[ $(echo $(basename "${i}" | cut -f 2 -d '.' | sed '/^\s*$/d')) == "dng" ]]; then echo "Single ISO DNG" fi #If we have a real Subject tag, extract info from it else exiftool "${i}" |grep --max-count=1 "Subject" | sed -e 's/.*: //g' fi ############################################## # 23 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Date/Time Original" | sed -e 's/.*: //g' | cut -d' ' -f1 | awk -F ":" '{print $3, $2, $1}' | sed -e 's/ /\//g' | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Date/Time Original" | sed -e 's/.*: //g' | cut -d' ' -f1 | awk -F ":" '{print $3, $2, $1}' | sed -e 's/ /\//g' else echo "errtag" fi ############################################## # 24 COLUMN if [[ $(exiftool "${i}" |grep --max-count=1 "Date/Time Original" | sed -e 's/.*: //g' | cut -d' ' -f2 | wc -l) -eq 1 ]]; then exiftool "${i}" |grep --max-count=1 "Date/Time Original" | sed -e 's/.*: //g' | cut -d' ' -f2 else echo "errtag" fi ############################################## # ENABLE THIS FOR CHECKING FILE NAMES. IF ENABLED, ALL FILES MUST CONTAIN 'IMG_' STRING OR OTHERWISE, THEY ARE EXCLUDED FROM THE STATISTICS! #Write this line/column only, if an invalid file name has been detected # if [[ "$ERRFILE" -eq 1 ]]; then # echo "errname" # fi ############################################## echo "newline" #this is written just as a dummy separator for each processed files for further line separation done below. ############################################## ####PROGRESSBAR STUFF - BEGIN # This section is increasing values seen in the kdialog processing window. let inc++ #Percentage needs to be calculated like this due to bash rounding limitations... PERCENT_VALUE=$((($mltp*$tics)/(200*$numargs/$inc % 2 + $mltp*$numargs/$inc))) qdbus $dbusRef Set "" "value" $PERCENT_VALUE; qdbus $dbusRef setLabelText "$LABELTEXT ($inc/$numargs)"; ####PROGRESSBAR STUFF - END shift ############################################## # Sort output: replace newlines with commas, remove more commas, replace 'newline' with a new line, trim the first and the last commas of any line. Sort lines by Date & Time (23th & 24th column) and write output done | tr '\n' ',' | sed -e 's/,[^,]*$//' -e 's/newline/\n/g' | sed -e 's/^,//g' -e 's/\(.*\),/\1/' | sort -t ',' -n -k23 -k24 | sed 's/inf/∞/g' > "${RAWDATA_TMP}" #| sed 's/newline/\n/g' | sort -u ############################################## #Close processing window if cancelled event has been triggered. ####PROGRESSBAR STUFF - BEGIN # If the process was cancelled, remove tmp file and exit the script. if [[ ! $(qdbus $dbusRef wasCancelled) == "false" ]]; then rm "${RAWDATA_TMP}" #We can delete the file because its existence has been checked before the processing window has been opened. Thus we don't get here, if the file already exists. exit fi ####PROGRESSBAR STUFF - END ########################################### #Add correct titles to the first row in RAWDATA_TMP file: sed -i '1s/^/Image File,File MD5Sum,Camera Temperature,ISO,Shutter Speed,Target Exposure,Exposure Compensation,Aperture,Target Aperture,Histogram Median,Focal Length,Hyperfocal Distance,Upper Focus Distance,Lower Focus Distance,Depth Of Field,Camera Model,Lens Model,Focus Mode,Exposure Mode,Live View,Camera Orientation,ISO Type,Date,Time\n/' "${RAWDATA_TMP}" #Close processing window if not cancelled and processing finished. ####PROGRESSBAR STUFF - BEGIN qdbus $dbusRef close ####PROGRESSBAR STUFF - END # SEL1 = "Apertures, Exposures & ISOs" true/false # SEL2 = "Focal Lengths & Lenses" true/false # SEL3 = "Temperatures & ISOs" true/false # SEL4 = "Shooting & Focus Modes" true/false # SEL5 = "Export Only (CSV)" true/false if [[ $SEL5 == true ]]; then kdialog --msgbox "EXIF data exported successfully"; exit fi elif [[ -e "${RAWDATA_TMP}" ]] && [[ $SEL5 == true ]]; then kdialog --msgbox "EXIF data exported already.\n\nFile:\n\n${RAWDATA_TMP}"; exit fi #KDIALOG PROCESSING WINDOW - END ############################################## # Check RAWDATA_TMP for bad line outputs # 1) BADFILES: Open written (or existing) CSV file # 2) BADFILES: List all lines matching pattern "errname" or "errtag" # 3) BADFILES: Write output as a single line, using comma mark to separate the written output (file names). Remove the last extra comma. BADFILES=$(cat "${RAWDATA_TMP}" | sed -ne '/errname/p' -ne '/errtag/p' | sed 's/,.*$//') BADFILES_COUNT=$(cat "${RAWDATA_TMP}" | sed -ne '/errname/p' -ne '/errtag/p' | sed 's/,.*$//' | wc -l) #Count lines found in the output of BADFILES. If not zero (e.g. bad strings found), then... if [[ $BADFILES_COUNT != 0 ]]; then cat "${RAWDATA_TMP}" | sed -e '/errname/d' -e '/errtag/d' > "/tmp/${FILENAME}-errtags${FILE_EXT}" RAWDATA_TMP_ERR="/tmp/${FILENAME}-errtags${FILE_EXT}" #We don't want to overwrite the original file. if [[ $(cat "${RAWDATA_TMP_ERR}" | wc -l) == 1 ]]; then #If not any valid output image files. Minimum count of lines is 2. kdialog --error "Could not process any input file:\n\n$BADFILES\n\nThis can be due to missing EXIF data such as Temperature, ISO, Date or Time.\n\nPlease check CSV file (${FILENAME}${FILE_EXT}) contents to study the problem.\n\nExiting."; rm "${RAWDATA_TMP_ERR}" exit elif [[ $(cat "${RAWDATA_TMP_ERR}" | wc -l) -le 2 ]]; then #if we have just a single file here. Minimum count of lines is 3. kdialog --error "Could not process a valid number of input files. Minimum count of valid files is 2.\n\nFiles that could not be processed:\n\n$BADFILES\n\nThis can be due to missing EXIF data such as Temperature, ISO, Date or Time.\n\nPlease check CSV file (${FILENAME}${FILE_EXT}) contents to study the problem.\n\nExiting." rm "${RAWDATA_TMP_ERR}" exit else mv "/tmp/${FILENAME}-errtags${FILE_EXT}" "${CSVFOLDER}/${FILENAME}-errtags${FILE_EXT}" RAWDATA_TMP="${CSVFOLDER}/${FILENAME}-errtags${FILE_EXT}" kdialog --msgbox "Could not process files:\n\n$BADFILES\n\nThis can be due to missing EXIF data such as Temperature, ISO, Date or Time.\n\nPlease exclude these files or check CSV file (${FILENAME}${FILE_EXT}) contents to study the problem.\n\nNew CSV file written as (bad files excluded):\n${RAWDATA_TMP}"; fi fi ###################################################################################### FILELIST=$(echo -n $(awk -F ',' 'FNR> 1 {print $1}' "${RAWDATA_TMP}" |sort -n |tr ' ' '\n' | sort -n | tr '\n' ',' | sed 's/,*\r*$//')) #Total count of accepted pictures, used for further data representation in gnuplot. We reduce it by 1 due to file header (column titles are not counted): ACCEPTED_TOTAL=$(echo -n $(($(cat "${RAWDATA_TMP}" | wc -l) - 1))) ############################################################################################################################################## ############################################################################################################################################## ############################################################################################################################################## ####GNUPLOT STUFF - BEGIN GNUPLOT_MAINWINDOW_TITLE=$(echo "$DIR_BASENAME ($ACCEPTED_TOTAL images, $FILENAME)") ########################################################### # GNUPLOT TIME VALUES #PLOT 1 # Should we use time values in the first plot? If too many images, basically rendered unreadable # Rotate x labels if there are too many of them if [[ $ACCEPTED_TOTAL -lt 10 ]]; then #Do not rotate x labels, if we have less than 10 images selected X_ROTATELABELS=$(echo -n "") if [[ $ACCEPTED_TOTAL -le 6 ]]; then #Time values are only if max 6 images selected X2_TIMESTRINGS=$(echo -n "set x2tics offset 0,-0.5") else X2_TIMESTRINGS=$(echo -n "unset x2tics") fi else X_ROTATELABELS=$(echo -n "set xtics rotate 90") fi ############################################################ #IMAGE COUNT/UNIT SCALES FOR GNUPLOT PLOTS 2 & 3 if [[ $ACCEPTED_TOTAL -le 10 ]]; then SCALE=1 elif [[ $ACCEPTED_TOTAL -gt 10 ]] && [[ $ACCEPTED_TOTAL -le 20 ]]; then SCALE=2 elif [[ $ACCEPTED_TOTAL -gt 20 ]] && [[ $ACCEPTED_TOTAL -le 40 ]]; then SCALE=4 elif [[ $ACCEPTED_TOTAL -gt 40 ]] && [[ $ACCEPTED_TOTAL -le 60 ]]; then SCALE=6 elif [[ $ACCEPTED_TOTAL -gt 60 ]] && [[ $ACCEPTED_TOTAL -le 80 ]]; then SCALE=8 elif [[ $ACCEPTED_TOTAL -gt 80 ]] && [[ $ACCEPTED_TOTAL -le 200 ]]; then SCALE=10 elif [[ $ACCEPTED_TOTAL -gt 200 ]] && [[ $ACCEPTED_TOTAL -le 400 ]]; then SCALE=20 elif [[ $ACCEPTED_TOTAL -ge 400 ]]; then SCALE=40 fi ############################################################################################################################################## ############################################################################################################################################## ############################################################################################################################################## # ISO VALUES #Do the following stuff only, if we have checked for any ISO related stuff in the kdialog selection. if [[ $SEL1 == true ]] || [[ $SEL3 == true ]]; then #ISO min max values # 1) Use awk to print field 3 from RAWDATA_TMP. Ignore the first row with FNR> 1 option. # 2) awk prints equivalent numbers as output. Merge them with "|sort -n" pipe. sort prints numbers starting from the smallest (first line) and ending to the greatest (last line) # 3) Strip the output, either first line (head -1) or the last one (tail -1). ISO_MIN_VALUE=$(echo -n $(awk -F ',' 'FNR> 1 {print $4}' "${RAWDATA_TMP}" | sort -n | head -1)) ISO_MAX_VALUE=$(echo -n $(awk -F ',' 'FNR> 1 {print $4}' "${RAWDATA_TMP}" | sort -n | tail -1)) #################################################################################################################### # ISO VALUES GENERATING RAWDATA_TMP2 #Get percentages for ISO values usage # OUTPUT template for RAWDATA_TMP3 is as follows: # ,, # Explanation for the following command: # 1) Use awk to print field 3 from RAWDATA_TMP. Ignore the first row with FNR> 1 option. # 2) awk prints equivalent numbers as output. Count and merge them with "|sort -n | uniq -c" pipe # 3) Output results leading white spaces. For each line, delete them with sed. # 4) use awk as pipe (awk starting with '{b[$2]=$1;sum=sum ...) to calculate percentage for the first column. First column has count number for each ISO value ("how many times ISO XX is used"). ISOs are defined in column 2. Print the output to a new column 3. # 5) In step 4, the output has too many decimals. As the output of this step is written to column 3, we use another awk pipe to strip too many decimals of the current column 3. To keep two first decimals, we use %.2f option. Print column 1 ($1) and 2 ($2) as they are, respectively. Add % mark and start a new line (\n) after each printf function. # 6) Replace spaces with commas for the final output, and write the final output to RAWDATA_TMP3. awk -F ',' 'FNR> 1 {print $4}' "${RAWDATA_TMP}" |sort -n | uniq -c | sed "s/^[ \t]*//" | awk '{b[$2]=$1;sum=sum+$1} END{for (i in b) print b[i],i,(b[i]/sum)*100}' | awk '{printf "%.0f %.0f %.2f'%'\n", $1,$2,$3}' | tr ' ' ',' > "${RAWDATA_TMP2}" #################################################################################################################### # ISO VALUES - MINIMUM, MAXIMUM, LEAST USED, MOST USED AND AVERAGE #What is the maximum number of matches for a single ISO value? MAX_MATCH_FOR_ISO=$(echo -n $(awk -F ',' '{print $1}' "${RAWDATA_TMP2}" | sort -n | tail -1)) #We store current min/max ISOvalues to a string variables WHATIS_REAL_MAX_ISO=$(echo -en "Max: $ISO_MAX_VALUE") # Returns column 3 value of RAWDATA_TMP E.G. 3200, based on max column 3 value of RAWDATA_TMP WHATIS_REAL_MIN_ISO=$(echo -en "Min: $ISO_MIN_VALUE") # Returns column 3 value of RAWDATA_TMP E.G. 200, based on min column 3 value of RAWDATA_TMP #Format: (1*400)+(1*1600)+(2*3200) ... ISO_DIVIDEND=$(echo -n $(($(awk -F ',' '{print "("$1,$2")"}' "${RAWDATA_TMP2}" | sort -n | sed -e 's/ /*/g' | tr '\n' '+' | sed 's/+[^+]*$//')))) #Just a basic average calculation ISO_AVERAGE=$(echo -e $(awk 'BEGIN {print "'"$ISO_DIVIDEND"'"/"'"$ACCEPTED_TOTAL"'"}' | awk '{printf "%.0f", $1}')) ########################################################## # ISO VALUES - CHECK FOR MIN AND MAX VALUES # 1) Get awk output of file RAWDATA_TMP3, separator for columns is comma mark, get column 3 ($3) # 2) Sort percentage values from lowest to greatest, starting from the lowest # 3) Get the match count for each percentage value (column 3 value) with 'uniq -c' # 4) Trim all leading white spaces for each printed line # 5) We have now two columns, separated by space. Get the first column with awk pipe, use space as a column separator, and print column 1 ($1) # 6) Get the first line. Output represents the number of matches for listed percentage. We check if it's not 1 in the following if statement. # The whole idea is that we can't give a true statement for "What is the least/most used ISO value" if multiple ISO values equal same percentage for usage MOSTUSED_ISO_CHECK=$(echo -n $(awk -F ',' '{print $3}' "${RAWDATA_TMP2}" | sort -n | uniq -c | sed "s/^[ \t]*//" | awk -F ' ' '{print $1}' | tail -1)) LEASTUSED_ISO_CHECK=$(echo -n $(awk -F ',' '{print $3}' "${RAWDATA_TMP2}" | sort -n | uniq -c | sed "s/^[ \t]*//" | awk -F ' ' '{print $1}' | head -1)) #The following gives a correct value ONLY IF there are unique values for EACH ISOs. Otherwise, the output is not as expected. That's why we need to check the values of MOST/LEASTUSED_ISO_CHECK first. MOSTUSED_ISO=$(echo -n $(awk -F ',' '{print $3,$2}' "${RAWDATA_TMP2}" | sort -n | awk -F ' ' '{print $2}' | tail -1)) LEASTUSED_ISO=$(echo -n $(awk -F ',' '{print $3,$2}' "${RAWDATA_TMP2}" | sort -n | awk -F ' ' '{print $2}' | head -1)) ########################################################## #In addition, we consider that minimum of 10 pictures must be accepted as input. Otherwise, user can read this info pretty easily just checking the gnuplot graphs. if [[ "$LEASTUSED_ISO_CHECK" -ne 1 ]]; then #If more than one, then... WHATIS_LEASTUSED_ISO=$(echo -n "") #Output string, nothing to say. elif [[ "$LEASTUSED_ISO_CHECK" -eq 1 ]]; then #Else if it's one, then... if [[ "$ACCEPTED_TOTAL" -gt 10 ]]; then #...we check the number of pictures. If it's greater than 10, then print the following string. WHATIS_LEASTUSED_ISO=$(echo -n ", Least used: $LEASTUSED_ISO") #Returns column 2 value of RAWDATA_TMP3 E.G. 400, based on max column 3 value of RAWDATA_TMP3 elif [[ "$ACCEPTED_TOTAL" -le 10 ]]; then #...we check the number of pictures. If it's equal or less than 10, we print nothing. WHATIS_LEASTUSED_ISO=$(echo -n "") #Output string, nothing to say fi fi if [[ "$MOSTUSED_ISO_CHECK" -ne 1 ]]; then #If more than one, then... WHATIS_MOSTUSED_ISO=$(echo -n "") #Output string, nothing to say. elif [[ "$MOSTUSED_ISO_CHECK" -eq 1 ]]; then #Else if it's one, then... if [[ "$ACCEPTED_TOTAL" -gt 10 ]]; then #...we check the number of pictures. If it's greater than 10, then print the following string. WHATIS_MOSTUSED_ISO=$(echo -n ", Most used: $MOSTUSED_ISO") #Returns column 2 value of RAWDATA_TMP3 E.G. 400, based on max column 3 value of RAWDATA_TMP3 elif [[ "$ACCEPTED_TOTAL" -le 10 ]]; then #...we check the number of pictures. If it's equal or less than 10, we print nothing. WHATIS_MOSTUSED_ISO=$(echo -n "") #Output string, nothing to say fi fi # Max ISO string: $WHATIS_REAL_MAX_ISO # Min ISO string: $WHATIS_REAL_MIN_ISO # Least used ISO string: $WHATIS_LEASTUSED_ISO # Most used ISO string: $WHATIS_MOSTUSED_ISO ########################################################### # ISO VALUES - SHIFT ISO RANGE VALUES FOR GNUPLOT # We shift down minimum ISO values to get a proper scale for gnuplot. Use "Less than" integer comparison because there can be ISO values such as 160, 250... #DO NOT CHANGE THE CHECK (ELIF EXECUTION) ORDER!! if [[ "$ISO_MIN_VALUE" -le 100 ]]; then #Less or equal than... ISO_MIN_VALUE_GNU=0 #Just scaling down, not a true ISO value elif [[ "$ISO_MIN_VALUE" -le 200 ]]; then ISO_MIN_VALUE_GNU=100 elif [[ "$ISO_MIN_VALUE" -le 400 ]]; then ISO_MIN_VALUE_GNU=200 elif [[ "$ISO_MIN_VALUE" -le 800 ]]; then ISO_MIN_VALUE_GNU=400 elif [[ "$ISO_MIN_VALUE" -le 1600 ]]; then ISO_MIN_VALUE_GNU=800 elif [[ "$ISO_MIN_VALUE" -le 3200 ]]; then ISO_MIN_VALUE_GNU=1600 elif [[ "$ISO_MIN_VALUE" -le 6400 ]]; then ISO_MIN_VALUE_GNU=3200 elif [[ "$ISO_MIN_VALUE" -le 8000 ]]; then ISO_MIN_VALUE_GNU=6400 fi if [[ "$ISO_MAX_VALUE" -ge 8000 ]]; then #Greater or equal than... ISO_MAX_VALUE_GNU=12800 elif [[ "$ISO_MAX_VALUE" -ge 6400 ]]; then ISO_MAX_VALUE_GNU=8000 elif [[ "$ISO_MAX_VALUE" -ge 3200 ]]; then ISO_MAX_VALUE_GNU=6400 elif [[ "$ISO_MAX_VALUE" -ge 1600 ]]; then ISO_MAX_VALUE_GNU=3200 elif [[ "$ISO_MAX_VALUE" -ge 800 ]]; then ISO_MAX_VALUE_GNU=1600 elif [[ "$ISO_MAX_VALUE" -ge 400 ]]; then ISO_MAX_VALUE_GNU=800 elif [[ "$ISO_MAX_VALUE" -ge 200 ]]; then ISO_MAX_VALUE_GNU=400 elif [[ "$ISO_MAX_VALUE" -ge 100 ]]; then ISO_MAX_VALUE_GNU=200 fi ########################################################### #Export all used ISO values GET_ISO_VALUES=$(echo -n $(awk -F ',' 'FNR> 1 {print $4}' "${RAWDATA_TMP}" | awk '!seen[$0]++' |sort -n | tr '\n' ',' | sed -e 's/,[^,]*$//')) ISO_TICSRANGE=$(echo -n $ISO_MIN_VALUE_GNU,$GET_ISO_VALUES,$ISO_MAX_VALUE_GNU) ########################################################### fi ############################################################################################################################################## ############################################################################################################################################## ############################################################################################################################################## # TEMPERATURE VALUES #Do the following stuff only, if we have checked for any ISO related stuff in the kdialog selection. if [[ $SEL3 == true ]]; then #################################################################################################################### #RAWDATA_TMP2 #Get percentages for temperature values # OUTPUT template for RAWDATA_TMP2 is as follows: # ,, # Explanation for the following command: # 1) Use awk to print field 2 from RAWDATA_TMP. Ignore the first row with FNR> 1 option. # 2) awk prints equivalent numbers as output. Count and merge them with "|sort -n | uniq -c" pipe # 3) Output results leading white spaces. For each line, delete them with sed. # 4) use awk as pipe (awk starting with '{b[$2]=$1;sum=sum ...) to calculate percentage for the first column. First column has count number for each temperature value ("how many matches for XX temperature"). Temperature values are defined in column 2. Print the output to a new column 3. # 5) In step 4, the output has too many decimals. As the output of this step is written to column 3, we use another awk pipe to strip too many decimals of the current column 3. To keep two first decimals, we use %.2f option. Print column 1 ($1) and 2 ($2) as they are, respectively. Add % mark and start a new line (\n) after each printf function. # 6) Replace spaces with commas for the final output, and write the final output to RAWDATA_TMP2. awk -F ',' 'FNR> 1 {print $3}' "${RAWDATA_TMP}" |sort -n | uniq -c | sed "s/^[ \t]*//" | awk '{b[$2]=$1;sum=sum+$1} END{for (i in b) print b[i],i,(b[i]/sum)*100}' | awk '{printf "%.0f %.0f %.2f'%'\n", $1,$2,$3}' | tr ' ' ',' > "${RAWDATA_TMP3}" #################################################################################################################### #Temperature min max values (actual values from the file) TEMP_MIN=$(echo -n $(awk -F ',' 'FNR> 1 {print $3}' "${RAWDATA_TMP}" | sort -n | head -1)) #Min Temp string TEMP_MAX=$(echo -n $(awk -F ',' 'FNR> 1 {print $3}' "${RAWDATA_TMP}" | sort -n | tail -1)) #Max Temp string #Format: (1*31)+(1*38)+(2*39) ... TEMP_DIVIDEND=$(echo -n $(($(awk -F ',' '{print "("$1,$2")"}' "${RAWDATA_TMP3}" | sort -n | sed -e 's/ /*/g' | tr '\n' '+' | sed 's/+[^+]*$//')))) #Just a basic average calculation TEMP_AVERAGE=$(echo -e $(awk 'BEGIN {print "'"$TEMP_DIVIDEND"'"/"'"$ACCEPTED_TOTAL"'"}' | awk '{printf "%.2f", $1}')) ############################################## #What is the maximum number of matches for a single temperature? MAX_MATCH_FOR_TEMP=$(echo -n $(awk -F ',' '{print $1}' "${RAWDATA_TMP3}" | sort -n | tail -1)) #Round temperature scale TEMP_MULTP=2 #Multiplier for temperature scale for plot 1. (scale only!) #TEMP_INCREMENT=2 #Temperature increment steps. For example, with value of 2, we get ...0, 2...10, 12, 14, 16...24... etc. # We set minimum temperature to - 2, rounding down UNROUNDED_MIN=$(echo -n $(($TEMP_MIN - $TEMP_MULTP))) # BASE LAYOUT FOR THE FOLLOWING AWK STUFF: # awk '{i=int($0/4);print((i==$0||$0>0)?i:i-1)*4}' # https://stackoverflow.com/questions/33085008/bash-round-to-nearest-multiple-of-4 MINVALUE_TEMP=$(echo -n $UNROUNDED_MIN | awk '{i=int("'"$UNROUNDED_MIN"'"/"'"$TEMP_MULTP"'");print((i=="'"$UNROUNDED_MIN"'"||"'"$UNROUNDED_MIN"'">0)?i:i-1)*"'"$TEMP_MULTP"'"}') # We set maximum temperature to + 2, rounding up UNROUNDED_MAX=$(echo -n $(($TEMP_MAX + $TEMP_MULTP))) # BASE LAYOUT FOR THE FOLLOWING AWK STUFF: # awk '{print$0+(n-$0%n)%n}' # https://stackoverflow.com/questions/33085008/bash-round-to-nearest-multiple-of-4 MAXVALUE_TEMP=$(echo -n $UNROUNDED_MAX | awk '{print"'"$UNROUNDED_MAX"'"+("'"$TEMP_MULTP"'"-"'"$UNROUNDED_MAX"'"%"'"$TEMP_MULTP"'")%"'"$TEMP_MULTP"'"}') fi ############################################################################################################################################## ############################################################################################################################################## ############################################################################################################################################## # SELECTION 3 - TEMPERATURES & ISOS ######################################################################################## # PLOT 1 (Images & Temperatures & ISOS) if [[ $SEL3 == true ]]; then #GNUPLOT, ACTUAL PROGRAM EXECUTION STARTS HERE: gnuplot < 1 {print $1}' "${RAWDATA_TMP}" |sort -n |tr ' ' '\n' | sort -n | tr '\n' ',' | sed 's/,*\r*$//')) #DEPRECATED # This syntax is used for md5sums check as well... ####################################################################### #(For temperatures?) Deprecated: #awk -F ',' 'FNR> 1 {print $2}' "${RAWDATA_TMP}" |sort -n | uniq -c | sed "s/^[ \t]*//" | tr ' ' ',' > "${RAWDATA_TMP2}" #Add some ISO and temperature statistics #paste <(echo "${ISO_ALL_COUNT}") <(echo "${TEMP_ALL_COUNT}") -d , > "${RAWDATA_TMP2}" #RAWDATA 2 FILE DATA ORDER AS FOLLOWS: #TEMPERATURE_COUNTS,TEMPERATURE_VALUE,ISO_USAGE_COUNTS,ISO_SPEED_VALUES # |awk '{print "("$0")"}' --brackets #ARG1=$1 #ARG2=$2 #ARG3=$3 #ARG4=$4 #ARG5=$5 #ARG6=$6 #gnuplot --persist -e "TITLE='${GNUPLOT_TITLE}'; RAWFILE='${RAWDATA_TMP}'; WINDOWTITLE='${GNUPLOT_MAINWINDOW_TITLE}'; ISO_MIN='${ISO_MIN_VALUE}'; ISO_MAX='${ISO_MAX_VALUE}'; ISO_VALUES='${GET_ISO_VALUES}';" $GNUPLOT_SCRIPT #ARG3='${ARG3}'; ARG4='${ARG4}'; ARG5='${ARG5}'; ARG6='${ARG6}'" $GNUPLOT_FILE # Max ISO string: $WHATIS_REAL_MAX_ISO # Min ISO string: $WHATIS_REAL_MIN_ISO # Least used ISO string: $WHATIS_LEASTUSED_ISO # Most used ISO string: $WHATIS_MOSTUSED_ISO