Drew
Drew

Reputation: 524

Bash find filename and set to variable

I want to find the name of a file in a folder on my server and set it to a variable to use it later. The problem is when I run my backup script the file name changes each time to compensate for the date. So I cannot just hard code the file name and path.

For example I know where the file will be - /var/backups/"unknownfilename.sql"

 backuppath="/var/backups/"

How can I set $backupfile to the file in $backuppath?

After researching I can only find where people echo out the filenames, they never end up storing them to a variable.

Upvotes: 3

Views: 16608

Answers (1)

Charles Duffy
Charles Duffy

Reputation: 295855

For bash (#!/bin/bash):

backuppath=/var/backups
sqlfiles=( "$backuppath"/*.sql )
[[ -e $sqlfiles ]] || { echo "Matched no files" >&2; exit 1; }

If you want to refer to the first match:

echo "The first match found was: $sqlfiles"

If you want to refer to all array contents:

echo "Found the following files:"
printf '- %q\n' "${sqlfiles[@]}"

For POSIX sh (#!/bin/sh) instead:

backuppath=/var/backups

# wrap in a function to avoid overwriting the global $1, $2, etc.
find_files() {
  set -- "$backuppath"/*.sql
  [ -e "$1" ] || { echo "Matched no files" >&2; exit 1; }
  [ "$#" -gt 1 ] && echo "WARNING: Matched $# files; only taking first" >&2
  sqlfile=$1
}
find_files

Points of note:

  • The expansion itself ("$backuppath") should be inside quotes; the glob expression (*.sql) should not.
  • Testing whether the first element found exists ([[ -e $sqlfiles ]] in bash, [ -e "$1" ] in the POSIX sh version) protects against default behavior when no matches exist, which will use the glob expression itself (/var/backups/*.sql) as a result; when tested for existence, this won't be present unless a file exists with literally that name (which is to say, a name containing an asterisk).
  • The first form uses two behaviors present in bash (the shell you tagged your question for), but not /bin/sh: Arrays, and the extended ([[ ]]) test operator. If you were to use the standard test command, it would be [ -e "$sqlfiles" ] instead; if you were to operate in a shell without arrays, you might wrap this logic in a function and use set -- "$backuppath"/*.sql to put results into the array-like object "$@", after which you could refer to the first match as "$1", or the full set of matches as "$@".

Upvotes: 9

Related Questions