purplehaze
purplehaze

Reputation: 33

Shell Scripting, remove a file without giving the entire name as a parameter

say we have a file named randomfile_a434534_Frank.csv

I want the user to input the the first portion "randomfile*" as the parameter not the entire thing. how will i be able to access/say delete this particular file without specfying the entire file name

Upvotes: 0

Views: 66

Answers (2)

Aif
Aif

Reputation: 11220

You could just use the user input to rm "$intput"* (or -i if you want the user to check which files are being deleted) but beware of the actual user input which could turn your script in an unintended maner.

Here is a small shell proof of concept:

$ touch aaJKL
$ toto=aa
$ rm -i "$toto"* # thanks Charles Duffy
rm: remove regular empty file `aaJKL'? y

What could happen?

  • user provides ../../../path/to/sensitive/file
  • user provides ./; <<nasty command>>; echo " and executes arbitrary command as pointed out by Charles, this kind of vulnerability only happens for string substitution before the shell performs syntax parsing (such as when generating a string to pass to system(), or when eval is used to force an additional parsing pass).
  • user uses a symbolic link to target another file

Another hint would be to prompt an inode number to the user, and ensure this inode number is legitimate.

For instance, you could do something like :

#!/usr/bin/env bash

echo "Choose a single file number you want to remove"
ls -i1 ./
read filenumber
if [[ $filenumber =~ ^[-+]?[0-9]+$ ]]; then
        find . -inum $filenumber -delete
else
        echo "Expect integer as an input"
fi

Sample output:

$ touch sample{1,2,3,4}
$ ./so.sh 
Choose a single file number you want to remove
1614159 sample1
1614160 sample2
1614161 sample3
1614162 sample4
fds
Expect integer as an input
$ ./so.sh 
Choose a single file number you want to remove
1614159 sample1
1614160 sample2
1614161 sample3
1614162 sample4
1614159

$ ./so.sh  # notice that sample1 was deleted
Choose a single file number you want to remove
1614160 sample2
1614161 sample3
1614162 sample4

Upvotes: 0

Charles Duffy
Charles Duffy

Reputation: 295403

The following reprompts until a prefix matching only a single file is given. Modify to taste -- removing the loop if you want to only test once, referring instead to $1 if you want to get the prefix from the command line, or iterating over "${files[@]}" in the event of multiple files matching instead of bailing/reprompting if such is your intent.

#!/bin/bash
# note that the above is necessary to enable features such as arrays; shells started
# with #!/bin/sh may not provide them.

while :; do
  echo "Please enter a filename prefix:" >&2
  IFS= read -r filename

  files=( "$filename"* )
  if (( ${#files[@]} == 1 )) && [[ -e "$files" ]]; then
    echo "OK; using $files" >&2
    break
  elif [[ ! -e "$files" ]] || (( ${#files[@]} == 0 )); then
    echo "Error: No matching files found" >&2
  else
    echo "Error: More than one file matches that prefix" >&2
  fi
done

echo "Operating on file named: $files"

Upvotes: 4

Related Questions