Update: Here is my current corrected version (do not trust blindly, I had typos involved too!)

#!/usr/bin/env bash

TEMPDIR="$(mktemp -d)"
mkdir --verbose -- "${TEMPDIR}/tests"
trap 'cd -- "${TEMPDIR}/tests" && rm --verbose --one-file-system -rf "${TEMPDIR:-/invalid/615e1a5d}/tests"; cd ..; rmdir --verbose -- "${TEMPDIR}"' EXIT

And an alternative variant in case there are only files without subdirectories involved under “tests”:

trap 'cd -- "${TEMPDIR}/tests" && rm --verbose --one-file-system -f -- "${TEMPDIR:-/invalid/615e1a5d}/tests/"*; cd ..; rmdir --verbose -- tests "${TEMPDIR}"' EXIT

Note, I use --verbose to explicitly list files, because this is for my Test system. If you copy this construct to use in your own normal scripts, you might want to remove the verbose flags for normal usage.


Down below is old version:

This is just a little small question if this is secure. This script is used to create a fresh test environment that should get deleted when script ends. trap command solves that issue fine. However, I am very, very afraid of doing rm -rf in context of variables, in case the variable happens to become empty due to user error (or later changes in script). So I will do this in multiple steps.

#!/usr/bin/env bash

TEMPDIR="$(mktemp -d)"
mkdir -f -- "${TEMPDIR}/tests"
trap 'cd -- "${TEMPDIR}/tests" && rm -rf tests && cd .. && rmdir -- ${TEMPDIR}' EXIT

# Here follows the script content, creating temporary files and manipulating them...
  1. Use a subdirectory, so the variable is not used by itself. So we have to use ${TEMPDIR}/tests each time instead just ${TEMPDIR}.
  2. When removing all files recursively, first enter into directory with cd, and only if that was successful delete all files recursively with a specific directory name. This should make sure that rm -rf is only executed if the temporary directory even exist and the variable is not resolved to empty.
  3. Off course go up one dir again and then remove the empty directory with rmdir, which will only remove empty directories.

I personally feel confident that this construct is safe, but would like to hear your opinions. Maybe I missed something important. It would be devastating. I don’t want to try out various ways to see if one of them is working correctly.


Edit: For anyone who does not create uncontrolled temporary directories, they could just use rm -f tests/* instead, so nothing is deleted recursively. I may go that route and avoid sub-directories in my test folder.

  • ThanksForAllTheFish@sh.itjust.works
    link
    fedilink
    arrow-up
    2
    ·
    21 hours ago

    This might go beyond what you were asking for, but I’m always more comfortable handling file paths, deletions and errors in Python.

    #!/usr/bin/env python3
    
    import shutil
    from pathlib import Path
    from tempfile import TemporaryDirectory
    
    # Refuse to run without Python's symlink-resistant cleanup.
    if not getattr(shutil.rmtree, "avoids_symlink_attacks", False):
        raise RuntimeError("Symlink-resistant cleanup is unavailable")
    
    with TemporaryDirectory(prefix="test-run-", dir="/tmp") as name:
        tests = Path(name) / "tests"
        tests.mkdir(mode=0o700)
        print(f"Created {str(tests)!r}", flush=True)
    
        try:
            # Put your test code here.
            (tests / "example.txt").write_text(
                "temporary data\n", encoding="utf-8"
            )
        finally:
            print(f"Cleaning {name!r}", flush=True)
    
    # The entire temporary directory has now been removed.
    
    • thingsiplay@lemmy.mlOP
      link
      fedilink
      arrow-up
      1
      ·
      20 hours ago

      Funny enough I’m writing (and wrote before) a Python script that is all about files and renaming. And this Bash script is about creating a test environment. Maybe its actually a good idea to write this in Python too.