Se você estiver usando o Bash e quiser um método 100% seguro (o que, eu acho, você quer, agora que aprendeu da maneira mais difícil que você deve lidar com nomes de arquivos a sério), aqui vai:
shopt -s nullglob
while IFS= read -r file; do
file=${file#* }
eval "file=$file"
cp "$file" Destination
done < <(
for f in *; do
printf '%s %q\n' "$(date -r "$f" +'%s')" "$f"
done | sort -rn | head -n10
)
Vamos dar uma olhada em suas várias partes:
for f in *; do
printf '%s %q\n' "$(date -r "$f" +'%s')" "$f"
done
Isso será impresso nos termos stdout do formulário
Timestamp Filename
em que timestamp é a data de modificação (obtida com a opção -r
para date
) em segundos, uma vez que Epoch e Filename são uma versão com aspas do nome de arquivo que pode ser reutilizado como entrada de shell (consulte help printf
e o especificador de formato %q
). Essas linhas são então ordenadas (numericamente, na ordem inversa) com sort
, e somente as 10 primeiras são mantidas.
Isso é então alimentado no loop while
. Os timestamps são removidos com a designação file=${file# *}
(isso elimina tudo até e incluindo o primeiro espaço), então a linha aparentemente perigosa eval "file=$file"
se livra dos caracteres de escape introduzidos por printf %q
, e finalmente podemos seguramente copie o arquivo.
Provavelmente não é a melhor abordagem ou implementação, mas 100% garantido como seguro em relação a qualquer nome de arquivo possível e conclui o trabalho. No entanto, isso tratará arquivos, diretórios e etc. regulares da mesma forma. Se você deseja restringir a arquivos regulares, adicione [[ -f $f ]] || continue
logo após a linha for f in *; do
. Além disso, não irá considerar arquivos ocultos. Se você quiser arquivos ocultos (mas não .
nem ..
, é claro), adicione shopt -s dotglob
.
Outra solução de Bash 100% é usar o Bash diretamente para classificar os arquivos. Aqui está uma abordagem usando um quicksort:
quicksort() {
# quicksorts the filenames passed as positional parameters
# wrt modification time, newest first
# return array is quicksort_ret
if (($#==0)); then
quicksort_ret=()
return
fi
local pivot=$1 oldest=() newest=() f
shift
for f; do
if [[ $f -nt $pivot ]]; then
newest+=( "$f" )
else
oldest+=( "$f" )
fi
done
quicksort "${oldest[@]}"
oldest=( "${quicksort_ret[@]}" )
quicksort "${newest[@]}"
quicksort_ret+=( "$pivot" "${oldest[@]}" )
}
Depois, classifique-os, mantenha os primeiros 10 e copie-os para o seu destino:
$ shopt -s nullglob
$ quicksort *
$ cp -- "${quicksort_ret[@]:0:10}" Destination
Igual ao método anterior, isso tratará arquivos, diretórios e etc. regulares da mesma forma e ignorará arquivos ocultos.
Para outra abordagem: se o seu ls
tiver os argumentos i
e q
, você poderá usar algo ao longo destas linhas:
ls -tiq | head -n10 | cut -d ' ' -f1 | xargs -I X find -inum X -exec cp {} Destination \; -quit
Isto mostrará o inode do arquivo, e find
pode executar comandos nos arquivos referenciados por seu inode.
A mesma coisa, isso também tratará diretórios, etc., não apenas arquivos regulares. Eu realmente não gosto desse, já que ele depende muito do formato de saída do ls
…