0

I'm creating a shell script to find and delete screenshots saved on my desktop. I'm trying to use mapfile to create an array of file paths.

However I'm struggling to manage it as my current code creates an array that has only a single element!

Worth mentioning that the commented out code succeeds in creating the array I want (if I pretend the word splitting isn't happening). I know that it isn't ideal as it's splitting the output into separate array elements but at least it's creating an array with more than one element!

Can anyone point me in the right direction because I've been looking up example of how to use mapfile and no success yet :(

Code:

declare -a files

mapfile -d '' files < <(find "$HOME/Desktop" -maxdepth 1 -type f -name "*.png")

# files=($(find "$HOME/Desktop" -maxdepth 1 -type f -name *.png))

echo "${#files[@]}"

Screenshot of current code

Cyrus
  • 84,225
  • 14
  • 89
  • 153
  • Add `-print0` to your find command. – jordanm Apr 02 '22 at 21:47
  • 2
    BTW, is there a reason to use `find` here this as opposed to `shopt -s nullglob; files=( "$HOME"/Desktop/*.png )`? – Charles Duffy Apr 02 '22 at 22:06
  • Honestly it's because I've only been learning shell scripting for a couple of weeks and haven't come across ```shopt``` yet. Will look into it now :) –  Apr 02 '22 at 22:07
  • The purpose of the `shopt -s nullglob` is to make sure that if there aren't any files found you get an empty array as output, instead of an array containing only a string like `/home/DCrawley/Desktop/*.png`. It's not the only way to detect that case; another common idiom is to do something like `files=( "$HOME"/Desktop/*.png ); [[ -e "${files[0]}" || -L "${files[0]}" ]] || { echo "No files found!" >&2; files=( ); }` – Charles Duffy Apr 02 '22 at 22:48
  • Oh nice one, and great explanation. I was reading through the manual [here](https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html) and it's a very dense read! So essentially your suggestion saves the files that match ```"$HOME"/Desktop/*.png``` to an array but with the edge case handling of ```shopt -s nullglob``` thrown in as well? Thank you for the succinct explanation :) –  Apr 02 '22 at 22:55
  • BTW, the reason `nullglob` isn't on by default (and why you might want to turn it back off with `shopt -u nullglob` when you don't need it) is so `ls *.txt` can fail with something like `ls: *.txt: file not found` instead of being the same as `ls` with no arguments when there aren't any `*.txt` files. The `failglob` option provides another alternative way to handle the case, making the shell trigger a failure when a glob has no matches instead of having the command being called be responsible for doing so. – Charles Duffy Apr 02 '22 at 23:03

1 Answers1

1

Thanks to @jordanm for spotting my mistake.

I needed to add the -print0 action to print the full file name followed by a null character as it was defaulting to print.

This is the corrected version without the unnecessary declare:

mapfile -d '' files < <(find "$HOME/Desktop" -maxdepth 1 -type f -name "*.png" -print0)