1

I have a shell script that needs to delete the file names from the /tmp directory. The file names must be detected from a list of file names passed to my script.

./deletetmpfiles.sh /var/moht/test1.pdf  /var/shif/log/test4.pdf 

Any number of files can be passed as arguments to the deletetmpfiles.sh script.

Considering the above example.

My script should delete /tmp/test1.pdf & /tmp/test4.pdf

Below is what I attempted.

echo "Deleting the following files as they got printed: $@"

cd /home/system/bey.de/invoices/send4print

if [ $? -eq 0 ]; then
  echo "Deleting the following on the server: $@"
  echo "rm -f /tmp/$(basename $@)"
  rm -f /tmp/$(basename $@)
fi

But it deletes only the first file from /tmp i.e /tmp/test1.pdf and misses deleting the remaining files.

Can you please suggest?

1

2 Answers 2

2

basename doesn't deal with multiple files:

NAME

basename - strip directory and suffix from filenames   

SYNOPSIS

  basename NAME [SUFFIX]    basename OPTION...NAME...

Unless the -a option is used (GNU Coreutils):

-a, --multiple
   support multiple arguments and treat each as a NAME

But it would break if the filenames have newlines.

And will fail in your command, since basename -a will return the arguments with new lines

basename "$@"
foo.pdf
bar.pdf

Which breaks the rm command since the arguments passes are separated by new lines.

This code apparently solves the problem

rm $(echo "$(basename -a "$@")")

but I'm not so sure of its validity.


Yo can then loop over the arguments:

for i in "$@"; do 
  echo "rm -f /tmp/$(basename "$i")"
  rm -f "/tmp/$(basename "$i")"
done

To deal with names with spaces, they must be properly escaped when passed to the script:

$ script.sh "foo bar.pdf"

Or

$ script.sh foo\ bar.pdf
5
  • 1
    oops. :) But yeah, correctly quoted, it should be fine with whitespace.
    – ilkkachu
    Commented Feb 6, 2021 at 15:04
  • GNU coreutils basename supports multiple arguments with -a (and -z for NUL-terminated output), but that doesn't make the rm easier...
    – Freddy
    Commented Feb 6, 2021 at 15:19
  • 1
    basename -a could be coerced to use, but it would break if the filenames have newlines. And -z would be pretty much impossible to use in a script. It might have been better if they'd not even implemented things like that.
    – ilkkachu
    Commented Feb 6, 2021 at 15:42
  • @ilkkachu If you want you can check my updated answer. Commented Feb 6, 2021 at 16:12
  • 1
    @schrodigerscatcuriosity, well, in that rm-echo-basename command, the step with echo adds the word splitting that adding quotes around "$(basename -a "$@")" inhibits. So you could just do rm $(basename -a "$@") instead. But that breaks on regular spaces too (so you need to change IFS), and uses the names as globs (so you need to disable that), which is pretty much why I didn't want to go there in the first place. :) It's better to do it with a loop (which we already have here!), that way the filenames are separate from the go, and stay separate for the whole time.
    – ilkkachu
    Commented Feb 6, 2021 at 17:14
-1

I would suggest getting a solid basic knowledge before proceeding to more complicated stuff.

As usually there are more ways to accomplish given task.

A fundamental question of your example is: "What exactly $@ stands for?"

Answer might be: "all the command line arguments as separate, individual strings." (Robbins & Beebe: Classic Shell Scripting)

If you want to process all the individual members of this argument, you would need a cycle.

Variant 1:

for file in "$@" ; do
  echo "Deleting the following on the server: $file"
  file=$(basename $file)
  echo "rm -f /tmp/$file"
  rm -f /tmp/$file
done

Variant 2:

until [ $# = 0 ]; do
  echo "Deleting the following on the server: $file"
  file=$(basename $file)
  echo "rm -f /tmp/$file"
  rm -f /tmp/$file
  shift
done

In variant 2 shift makes the argument list shorter every iteration.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .