1

I made this simple bash script to take a full-screen screenshot and save it to the pictures folder

#!/usr/bin/bash

xfce4-screenshooter -f -s /home/rgcodes/Pictures/Screenshot_$scrshotcount.png 
let "scrshotcount++"

...which runs into a problem. scrshotcount is a global variable I defined in /etc/environment to be incremented every time the script runs. However, the script fails to increment the variable globally, and causes the script to just overwrite the previous screenshot. Searches on Google and Stack Overflow revealed that the problem isn't straightforward at all (something about child shells being unable to change variables for parents), and finding some other method would be better.

Here's my question. How do we append numbers (in ascending order) to the screenshots the script throws out so that they are saved just like those taken on Windows?(Windows auto-suffixes matching filenames, rather than overwriting them, so all Screenshots have the same name 'Screenshot' and the number of times the screenshot command has been used.)

I am using @erikMD's method as a temporary stop-gap for now.

rgcodes
  • 15
  • 6
  • 1
    you could simplify things quite a bit by appending a datetime to the output screen .png file name: `xfce4-screenshooter -f -s /home/rgcodes/Pictures/Screenshot_$(date +"%Y_%m_%d_%I_%M_%S_%p").png`. – j_b Jul 29 '21 at 16:53
  • if you really want to have the count appended to the screenshot name then you could do something like `xfce4-screenshooter -f -s /home/rgcodes/Pictures/Screenshot_$(awk '{print $1}' <(wc -l <(ls /home/grcodes/Pictures/Screenshot*.png))).png`. This command counts the number files named 'Screenshot*.png' (the asterisk is a wildcard) and uses that count in the new screenshot image file name. One caveat is that if there are no screenshots, then the first screenshot will be named 'Screenshot_0.png' – j_b Jul 29 '21 at 17:29
  • The counter method overwrites a newer screenshot if an older one is deleted. – rgcodes Jul 30 '21 at 17:08

3 Answers3

2

In addition to the excellent advice about using a date instead of a counter, here's a way to use a counter :/

dir=$HOME/Pictures

# find the current maximum value
current_max=$( 
    find "$dir" -name Screenshot_\*.png -print0 \
    | sort -z -V \
    | tail -z -n 1
)
if [[ ! $current_max =~ _([0-9]+)\.png ]]; then
    echo "can't find the screenshot with the maximum counter value" >&2
    exit 1
fi

# increment it
counter=$(( 1 + ${BASH_REMATCH[1]} ))

# and use it
xfce4-screenshooter -f -s "$dir/Screenshot_${counter}.png"

You'll have to manually create the Screenshot_1.png file.

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • It dosen't seem to work. Terminal returns "Can't find maximum counter value" even though I have ```Screenshot_1``` in the specified directory. @j_b method too dosen't seem to work, could they both be caused by the same reason? My shebang is ```#!/usr/bin/bash``` btw – rgcodes Jul 30 '21 at 05:32
  • Oh, I got my find command wrong: `find "$dir" -name Screenshot_\*.png -print0` – glenn jackman Jul 30 '21 at 13:18
  • Returns ```/usr/bin/scrshot2: line 10: warning: command substitution: ignored null byte in input can't find the screenshot with the maximum counter value ``` I also fixed the spelling error in the first line, still no joy. – rgcodes Jul 30 '21 at 13:50
  • Run it with `bash -x` and show the output – glenn jackman Jul 30 '21 at 13:54
  • ```+ dir=/home/rgcodes/Pictures ++ find /home/rgcodes/Pictures -name 'Screenshot_*.png' -print0 ++ tail -z -n 1 ++ sort -z -V /usr/bin/scrshot2: line 10: warning: command substitution: ignored null byte in input + current_max='/home/rgcodes/Pictures/WhatsApp Unknown 2021-07-21 at 18.34.48/Screenshot_2021-06-17_02-46-36.png' + [[ ! /home/rgcodes/Pictures/WhatsApp Unknown 2021-07-21 at 18.34.48/Screenshot_2021-06-17_02-46-36.png =~ _([0-9]+)\.png ]] + echo 'can'\''t find the screenshot with the maximum counter value' can't find the screenshot with the maximum counter value + exit 1 ``` – rgcodes Jul 30 '21 at 16:33
  • 1
    I created a new sub-folder and it now works. Please correct the spelling error in the first line though, and thanks a lot for your help! – rgcodes Jul 30 '21 at 17:10
  • Well, yeah, if you're using files with date suffix, then that regex won't find any files with a plain counter suffix. – glenn jackman Jul 30 '21 at 18:58
2

@rgcodes below is a script that will capture screenshots with a numeric count indicator per your original post. (tested it on Ubuntu 20.04)

Script contents:

#!/bin/bash

set -uo pipefail

# add source file and line number to xtrace output 
# i.e. when running:  bash -x ./your_script_name.sh
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'

capture_screenshot() {
    local output_dir="${1:-/tmp/screenshot}"
    local img_name="${2:-Screenshot}"
    local img_ext="${3:-png}"
    
    # create output directory (if not already existing)
    mkdir -p "${output_dir}"

    # get the last image in the sorted ls output
    local latest_png=$(tail -n 1 \
        <(sort -n -t _ -k 2 \
        <(ls ${output_dir}/*.${img_ext} 2> /dev/null)))

    # use the latest image to determine img_cnt value for next image
    local img_cnt=0
    if [[ ${latest_png} =~ _([0-9]+)\.png ]]; then
        img_cnt=$((1+${BASH_REMATCH[1]}))
    elif [[ ${latest_png} =~ ${img_name}.${img_ext} ]] ; then
        img_cnt=1
    fi

    # build path to output image
    local img_path="${output_dir}/${img_name}_${img_cnt}.${img_ext}"
    
    # remove count from output image path if count == 0
    if [[ "${img_cnt}" -eq "0" ]] ; then
        img_path="${output_dir}/${img_name}.${img_ext}"
    fi        

    xfce4-screenshooter -f -s "${img_path}"
}

capture_screenshot "$@"

The uses the following as defaults, but you can change them to meet your requirements.

output directory for screenshots:
/tmp/screenshot

base screenshot image name:
Screenshot

screenshot file extension:
.png

The script will attempt to create the output directory if it does not already exist (subject to user permission for creation). Below is a sample usage.

Prior to initial script execution, the output directory does not exist:

$ ls screenshot
$

Initial execution (directory is created and Screenshot.png created:

$ ./script.sh 
$ ls /tmp/screenshot/
Screenshot.png

Subsequent executions:

$ ./script.sh 
$ ls /tmp/screenshot/
Screenshot_1.png  Screenshot.png
$ ./script.sh 
$ ls /tmp/screenshot/
Screenshot_1.png  Screenshot_2.png  Screenshot.png
j_b
  • 1,975
  • 3
  • 8
  • 14
  • 2
    Looks good! but what happens if one of the Screenshots has been removed since the first run of the script? – ErikMD Jul 30 '21 at 16:40
  • @ErikMD nice catch. That is a problematic scenario as currently implemented. I may have some time later today to handle this situation as well. – j_b Jul 30 '21 at 16:51
1

Indeed, as suggested by @j_b in the comments, you should definitely give a try to using a timestamp with the command date +"$format".

FTR, the same idea is implemented here in this project of a gnome-screenshot bash wrapper
(disclaimer: I am the author of this repo).

Example command:

date "+%Y-%m-%d_%H-%M-%S"

↓

2021-07-29_19-13-30

So the overall script could just be something like:

#!/usr/bin/env bash

xfce4-screenshooter -f -s "$HOME/Pictures/Screenshot_$(date "+%Y-%m-%d_%H-%M-%S").png"

(Note that I added missing double-quotes, and modified your shebang, as /usr/bin/env bash is more portable than /bin/bash or /usr/bin/bash.)

ErikMD
  • 13,377
  • 3
  • 35
  • 71