The Handbook

    Theme
    • Guides
        • Check a system before installing FreeBSD
        • Orient a Linux administrator on FreeBSD
        • Supported FreeBSD releases
        • Choose a FreeBSD documentation and support channel
        • Move files safely without GNU mv -t
        • Update, upgrade, or update packages?
        • Upgrade 14.4 or 15.0 to FreeBSD 15.1
        • Choose packages, ports, or poudriere
        • Choose the quarterly or latest package branch
        • Choose a FreeBSD download or package mirror
        • Make a system setting persistent
        • Configure locale, keyboard, and time zone
        • Configure a serial console for recovery
        • Choose a custom kernel, module, or loader setting
        • Run a Linux binary with the compatibility layer
        • Check desktop and laptop hardware before installation
        • Choose and check a graphics driver
        • Choose Xorg or Wayland
        • Build a maintainable desktop baseline
        • Install and check a desktop browser
        • Check laptop Wi-Fi, power, and suspend
        • Check multimedia readiness
        • Choose and configure a printing stack
        • Run Windows applications with Wine
        • Snapshot and replicate a ZFS dataset
        • Choose a filesystem and storage layout
        • Operate ZFS without losing the recovery path
        • Restore files from a ZFS snapshot
        • Read ZFS pool health and run a scrub
        • Replace a failed device in a ZFS mirror
        • Replicate a ZFS dataset over SSH
        • Change PF safely on a remote host
        • Configure a narrow WireGuard tunnel
        • Plan a FreeBSD home server
        • Choose a mail server or an outgoing relay
        • Publish a network service safely
        • Choose a jail network model
        • Choose native jails or a jail manager
        • Choose a jail or a bhyve virtual machine
        • Establish a FreeBSD security baseline
        • Choose a MAC policy
        • Audit security-relevant activity
        • Start a DTrace performance investigation
    • Integrations
        • Create a first jail with Bastille
        • Compare jail managers and OCI tooling
        • Publish a Bastille service through PF
        • Mount a ZFS dataset in a Bastille jail
        • Update and upgrade Bastille jails
        • Back up and restore a Bastille jail
        • Prepare bhyve and vm-bhyve
        • Choose NFS or Samba for file sharing
        • Choose ZFS backup automation
        • Operate a signed poudriere repository
        • Manage FreeBSD configuration with Ansible or Salt
        • Run Motion with webcamd on FreeBSD
        • Design a reverse proxy, certificates, and monitoring
    • FAQ
      • Troubleshooting
          • Recover an interrupted freebsd-update run
          • Resolve a package repository or ABI mismatch
          • Diagnose the FreeBSD boot path
          • Recover with a ZFS boot environment
          • Diagnose DNS, routing, and firewall paths
          • Diagnose network mbuf exhaustion
          • Bind a service to a low port without running it as root
          • Diagnose audio output or input
          • Diagnose webcamd, cuse, and a webcam
          • Fix USB device permissions without opening every device
      • About this handbook
      • Synopsis
      • Translate a fixed command
      • Use shell expansions only when their behavior is intended
      • Move generated pathnames one at a time
      • Batch large selections without losing the final destination
      • Distinguish moving from renaming
      • Account for filesystem boundaries
      • Primary references

      Move files safely without GNU mv -t

      Last reviewed
      13 August 2026
      Applies to
      15.1-RELEASE, 15.0-RELEASE, 14.4-RELEASE

      Synopsis #

      FreeBSD mv(1) does not implement GNU coreutils -t or --target-directory. Its native multiple-source form places the destination directory last:

      $ mv source ... directory
      

      That operand order is sufficient for named files and shell expansions. Commands that generate an arbitrary number of pathnames need a different arrangement because the destination must remain the final operand. Use find -exec with one move per pathname for clarity, or a small shell wrapper for bounded batches.

      Translate a fixed command #

      A GNU command such as:

      $ mv -t archive -- report.txt image.png
      

      becomes:

      $ test -d archive
      $ mv -- report.txt image.png archive/
      

      The explicit test prevents an absent destination from changing the interpretation of the final operand. The -- marker ends option parsing, so a source name beginning with - is treated as a pathname. A trailing slash communicates that the final operand is expected to be a directory, although the preceding test remains the clear precondition.

      Add -n when existing destination names must remain untouched:

      $ mv -n -- report.txt image.png archive/
      

      FreeBSD mv -n skips an existing destination without prompting. Confirm the resulting source and destination inventories because a zero exit status can include skipped files.

      Use shell expansions only when their behavior is intended #

      This ordinary form moves visible entries matched by the shell:

      $ test -d archive
      $ mv -- incoming/* archive/
      

      It does not include names beginning with .. In a POSIX-style shell, an unmatched pattern can remain a literal operand and produce an error. Do not add broad dot patterns such as incoming/.*; they are easy to misread and have historical . and .. hazards.

      Use find when hidden names, depth, type, or an empty input set matter.

      Move generated pathnames one at a time #

      The clearest native replacement for a GNU find ... -exec mv -t destination {} + command moves one matched pathname per invocation:

      $ test -d archive
      $ find incoming -type f -exec mv -n -- {} archive/ \;
      

      find supplies each pathname as a distinct argument, so spaces, tabs, newlines, wildcard characters, and leading hyphens do not need text parsing. This example moves regular files below incoming; it deliberately leaves directories in place.

      Remove -n only after the overwrite policy is explicit. Add selection expressions such as -name or -mtime only after printing the exact same selection for review:

      $ find incoming -type f -mtime +30 -print
      

      Then append the -exec action to the reviewed expression.

      Batch large selections without losing the final destination #

      One process per file is often adequate for administrative work. For a large selection, a shell wrapper can reserve its first argument for the destination and pass the remaining batch to mv:

      $ test -d archive
      $ find incoming -type f -exec sh -c '
          destination=$1
          shift
          mv -n -- "$@" "$destination"
      ' move-to archive/ {} +
      

      In this invocation, move-to becomes the shell’s $0, archive/ becomes $1, and the pathnames supplied by find follow it. After shift, the source pathnames remain in "$@" and the destination is appended as the final operand.

      Keep the wrapper literal and small. Constructing a command line by concatenating find output, parsing ls, or interpolating pathnames into shell code reintroduces quoting and command-injection problems.

      Distinguish moving from renaming #

      With exactly two operands, mv source target may either rename source to target or place it inside target when target is a directory. GNU mv -T removes that directory interpretation; FreeBSD mv has no direct -T equivalent.

      For an exact rename, establish the intended preconditions first:

      $ test -e source
      $ test ! -e target && test ! -L target
      $ mv -- source target
      

      These shell checks do not make a shared writable directory race-free. Another process can create target after the check. A program that needs an atomic no-replace or exact-target guarantee should use an appropriate system call and verify its platform semantics instead of wrapping mv with a check.

      FreeBSD mv -h addresses a narrower case: with two operands, it treats a destination symlink as the target itself instead of following a symlink to a directory. It is not a general replacement for GNU -T.

      Account for filesystem boundaries #

      Within one filesystem, mv normally uses rename(2). Across filesystems, FreeBSD mv copies the object and then removes the source after the copy succeeds. That operation is not an atomic rename, may take substantial time, and can leave already completed items at the destination when a later item fails.

      Before a large cross-filesystem move:

      1. confirm destination capacity;
      2. decide whether existing names may be replaced;
      3. preserve an independent backup when the data is not reproducible;
      4. move a representative sample;
      5. verify the destination before treating absence at the source as success.

      Use Make a system setting persistent as a model for another common portability boundary: translate the intended mechanism instead of installing a familiar Linux command solely to preserve copied syntax.

      Primary references #

      • mv(1)
      • FreeBSD mv source for 15.1-RELEASE
      • find(1)
      • sh(1)
      • rename(2)
      • GNU coreutils target-directory option

      Independent documentation. Not affiliated with or endorsed by the FreeBSD Project or the FreeBSD Foundation.

      Report a bug
      • Synopsis
      • Translate a fixed command
      • Use shell expansions only when their behavior is intended
      • Move generated pathnames one at a time
      • Batch large selections without losing the final destination
      • Distinguish moving from renaming
      • Account for filesystem boundaries
      • Primary references