Depends on what you mean by "a single command", which is an unusual requirement. Generally speaking, you could use find
or a for
loop over a wildcard:
with find
:
find . -type f -exec sh -c 'for f; do [ $(wc -l < "$f") -eq 2 ] && mv -- "$f" /target/dir/; done' findshell {} +
with for
:
for f in ./*; do [ -f "$f" ] && [ $(wc -l < "$f") -eq 2 ] && mv -- "$f" /target/dir; done
If you instead have a list of files, perhaps with ksh93 and an array variable -- files=( * )
, for example -- you could loop over those filenames:
for f in "${files[@]}"; do [ -f "$f" ] && [ $(wc -l < "$f") -eq 2 ] && mv -- "$f" /target/dir; done
In the find
solution, we limit the results to "file" types; for each of those, we execute a shell with as many arguments as will fit (the {} +
part of the syntax); that shell is given 'findshell' as ARG[0], simply as a placeholder. The rest of the arguments are examined in the inner for
loop; those that have exactly two lines are moved.
In the for
solutions, we loop over the resulting file list and check to ensure we're looking at a regular file [ -f "$f" ]
and that the file contains exactly two lines. If both of those conditions match, we move the file.
In all of the mv
cases, we explicitly end the options using --
before giving the filename so that filenames that happen to begin with a -
dash are not unintentionally mistaken as options. This is also why the manual for
loop uses ./*
as the wildcard, so that all of the expanded filenames start with ./
, preventing those filenames from starting with a dash.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…