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:
- confirm destination capacity;
- decide whether existing names may be replaced;
- preserve an independent backup when the data is not reproducible;
- move a representative sample;
- 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.