J'ai un répertoire avec des milliers de fichiers. Comment puis-je déplacer 100 des fichiers (n'importe quel fichier fera l'affaire) vers un autre emplacement.
for file in $(ls -p | grep -v / | tail -100)
do
mv $file /other/location
done
Cela suppose que les noms de fichiers ne contiennent pas de blancs, de nouvelle ligne (en supposant que la valeur par défaut de $IFS
), caractères génériques (?
, *
, [
) ou commencez par -
.
C'est plus simple dans zsh:
mv -- *([1,100]) /other/location/
Cela déplace les 100 premiers fichiers non masqués (de tout type, modifiez ([1,100])
à (.[1,100])
pour les fichiers réguliers uniquement, ou (^/[1,100])
pour tout type mais répertoire ) dans l'ordre lexicographique du nom. Vous pouvez sélectionner un ordre de tri différent avec le o
qualificatif glob , par ex. pour déplacer les 100 fichiers les plus anciens:
mv -- *(Om[1,100]) /other/location/
Avec d'autres coquilles, vous pouvez le faire en boucle avec une sortie anticipée.
i=0
for x in *; do
if [ "$i" = 100 ]; then break; fi
mv -- "$x" /other/location/
i=$((i+1))
done
Une autre façon portable serait de construire la liste des fichiers et supprimer tous sauf les 100 derniers .
Si vous n'utilisez pas zsh:
set -- *
[ "$#" -le 100 ] || shift "$(($# - 100))"
mv -- "$@" /target/dir
Déplacerait les 100 derniers (par ordre alphabétique).
Ce qui suit a fonctionné pour moi. Désolé s'il a été publié précédemment, mais je ne l'ai pas vu dans une analyse rapide.
ls path/to/dir/containing/files/* | head -100 | xargs -I{} cp {} /Path/to/new/dir
L'oneliner suivant dans Shell aiderait.
foreach i (`find Source_Directory -type f --max-depth 1 | tail -100`); faire; {mv $ i Target_Directory}; terminé
shuf -n 100 -e * | xargs -i mv {} path-to-new-folder
mmv est un utilitaire exceptionnel qui vous permettra également de renommer en masse les fichiers. (J'ai dû Sudo apt-get install mmv
sur mon ordinateur pour l'installer.) Exemple d'utilisation simple: supposons que vous ayez un répertoire de fichiers avec l'extension .JPG que vous voudriez changer en .jpg en minuscules. La commande suivante fait l'affaire:
mmv \*.JPG \#1.jpg
La barre oblique inverse est utilisée pour indiquer qu'un caractère générique est à venir. Le */JPG correspond à tout ce qui a une extension JPG. Dans la partie "à" de la commande, le # 1 utilise le texte correspondant du premier caractère générique pour renommer le fichier. Bien sûr, vous pouvez mettre un chemin différent avant le # 1 pour déplacer également le fichier.
#!/bin/bash
c=1; d=1; mkdir -p NEWDIR_${d}
for jpg_file in *.jpg
do
if [ $c -eq 100 ]
then
d=$(( d + 1 )); c=0; mkdir -p NEWDIR_${d}
fi
mv "$jpg_file" NEWDIR_${d}/
c=$(( c + 1 ))
done
essayez ce code
la commande suivante fonctionne, si vous souhaitez utiliser ls
$ ls -rt source/* | head -n100 | xargs cp -t destination
Comment cela marche-t-il ??
ls -rt source/*
- la commande répertorie tous les fichiers avec le chemin relatifhead -n100
- prend les 100 premiers fichiersxargs cp -t destination
- déplace ces fichiers dans le dossier de destinationEssaye ça:
find /source/directory -type f -maxdepth 1 -print | tail -100 | xargs -J % mv % /other/location/
Si vous voulez être sûr/gérer les noms de fichiers avec des espaces, des nouvelles lignes, des guillemets, des barres obliques inverses, etc., vous devez utiliser des séparateurs à terminaison nulle:
find "$srcdir" -maxdepth 1 -type f -print0 | head -z -n 100 | xargs -0 -r -- mv -t "$destdir" --
EDIT2: REMARQUE: si vous n'avez pas head -z
( pour quelque raison que ce soit ) vous pouvez remplacer ce qui précède head -z -n 1000
avec tr '\0\n' '\n\0' | head -n 1000 | tr '\0\n' '\n\0'
(ou voir d'autres façons )
-maxdepth 1
évitera de rechercher des fichiers dans les sous-répertoires de $srcdir
, donc les seuls répertoriés sont les fichiers dans $srcdir
.-print0
utilisera \0
au lieu de la nouvelle ligne (\n
) entre chaque fichier répertorié - cela permet de gérer les fichiers contenant des sauts de ligne et des espaces avec xargs.head -z
comptera \0
terminé (au lieu de la nouvelle ligne (\n
) terminées) comme lignes. -n 100
affichera uniquement le premier 100
fichiers que find
a trouvés.
Si vous voulez voir quelle commande xargs
va exécuter, ajoutez -t
(ou --verbose
).xargs -0
"Les éléments d'entrée se terminent par une valeur nulle (\0
) au lieu de par des espaces, et les guillemets et les barres obliques inverses ne sont pas spéciaux (chaque caractère est pris littéralement) "xargs -r
ne fonctionnera pas mv
s'il n'y a aucun fichier à déplacer (c'est-à-dire si find
n'a trouvé aucun fichier).--
termine le traitement des arguments comme options du programme, plus de détails ici
Exemple de sortie (exécute une commande mv
et peut également gérer les fichiers avec des sauts de ligne dans leur nom):
$ find /tmp/t -maxdepth 1 -type f -print0 | head -z -n 100 | xargs -t -0 -r -- mv -t /tmp -- ; echo "exit codes: ${PIPESTATUS[@]}"
mv -t /tmp -- /tmp/t/file containing quotes"' then spaces /tmp/t/file containing quotes"' /tmp/t/file containing a slash n here\n /tmp/t/file containing a new line here
and continues /tmp/t/s /tmp/t/-x and -L 1. /tmp/t/of replace-str in the initi /tmp/t/-thisfile_starts_with_a_hyphen and has spaces and a -hyphen here /tmp/t/-thisfile_starts_with_a_hyphen and has spaces /tmp/t/-thisfile_starts_with_a_hyphen /tmp/t/another with spaces /tmp/t/one with spaces /tmp/t/c /tmp/t/a
exit codes: 0 0 0
$ ls -1R /tmp/t
/tmp/t:
a
'another with spaces'
b
c
'file containing a new line here'$'\n''and continues'
'file containing a slash n here\n'
'file containing quotes"'\'''
'file containing quotes"'\'' then spaces'
'of replace-str in the initi'
'one with spaces'
s
'some dir'
-thisfile_starts_with_a_hyphen
'-thisfile_starts_with_a_hyphen and has spaces'
'-thisfile_starts_with_a_hyphen and has spaces and a -hyphen here'
'-x and -L 1.'
/tmp/t/b:
'file with spaces'
'/tmp/t/some dir':
'some file'
Pour find
:
-maxdepth levels
Descend at most levels (a non-negative integer) levels of direc‐
tories below the starting-points. -maxdepth 0
means only apply the tests and actions to the starting-points
themselves.
-type c
File is of type c:
b block (buffered) special
c character (unbuffered) special
d directory
p named pipe (FIFO)
f regular file
l symbolic link; this is never true if the -L option or the
-follow option is in effect, unless the symbolic link is
broken. If you want to search for symbolic links when -L
is in effect, use -xtype.
s socket
D door (Solaris)
-P Never follow symbolic links. This is the default behaviour.
When find examines or prints information a file, and the file is
a symbolic link, the information used shall be taken from the
properties of the symbolic link itself.
-L Follow symbolic links. When find examines or prints information
about files, the information used shall be taken from the prop‐
erties of the file to which the link points, not from the link
itself (unless it is a broken symbolic link or find is unable to
examine the file to which the link points). Use of this option
implies -noleaf. If you later use the -P option, -noleaf will
still be in effect. If -L is in effect and find discovers a
symbolic link to a subdirectory during its search, the subdirec‐
tory pointed to by the symbolic link will be searched.
When the -L option is in effect, the -type predicate will always
match against the type of the file that a symbolic link points
to rather than the link itself (unless the symbolic link is bro‐
ken). Actions that can cause symbolic links to become broken
while find is executing (for example -delete) can give rise to
confusing behaviour. Using -L causes the -lname and -ilname
predicates always to return false.
Pour head
:
-n, --lines=[-]NUM
print the first NUM lines instead of the first 10; with the
leading '-', print all but the last NUM lines of each file
-z, --zero-terminated
line delimiter is NUL, not newline
EDIT: Quelqu'un mentionné qu'il n'avait pas head -z
, voici la version que j'utilisais (dans Fedora 25):
$ head --version
head (GNU coreutils) 8.25
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by David MacKenzie and Jim Meyering.
$ rpm -qf /usr/bin/head
coreutils-8.25-17.fc25.x86_64
Pour xargs
:
-0, --null
Input items are terminated by a null character instead of by
whitespace, and the quotes and backslash are not special (every
character is taken literally). Disables the end of file string,
which is treated like any other argument. Useful when input
items might contain white space, quote marks, or backslashes.
The GNU find -print0 option produces input suitable for this
mode.
-r, --no-run-if-empty
If the standard input does not contain any nonblanks, do not run
the command. Normally, the command is run once even if there is
no input. This option is a GNU extension.
-P max-procs, --max-procs=max-procs
Run up to max-procs processes at a time; the default is 1. If
max-procs is 0, xargs will run as many processes as possible at
a time. Use the -n option or the -L option with -P; otherwise
chances are that only one exec will be done. While xargs is
running, you can send its process a SIGUSR1 signal to increase
the number of commands to run simultaneously, or a SIGUSR2 to
decrease the number. You cannot increase it above an implemen‐
tation-defined limit (which is shown with --show-limits). You
cannot decrease it below 1. xargs never terminates its com‐
mands; when asked to decrease, it merely waits for more than one
existing command to terminate before starting another.
Please note that it is up to the called processes to properly
manage parallel access to shared resources. For example, if
more than one of them tries to print to stdout, the ouptut will
be produced in an indeterminate order (and very likely mixed up)
unless the processes collaborate in some way to prevent this.
Using some kind of locking scheme is one way to prevent such
problems. In general, using a locking scheme will help ensure
correct output but reduce performance. If you don't want to
tolerate the performance difference, simply arrange for each
process to produce a separate output file (or otherwise use sep‐
arate resources).
-t, --verbose
Print the command line on the standard error output before exe‐
cuting it.
Pour cp
:
-t, --target-directory=DIRECTORY
copy all SOURCE arguments into DIRECTORY
-v, --verbose
explain what is being done
Je suis venu ici, mais j'avais besoin de copier des fichiers en parties (99 chacun) de /DIR1
Vers /DIR2
. Je vais coller le script ici pour aider les autres, peut-être:
#!/bin/bash
# Thanks to <Jordan_U> @ #ubuntu
# 06 Dec 2014
i=0
copy_unit=98
for file in /DIR1/*; do
cp "$file" /DIR2
if [[ "$i" -ge "$copy_unit" ]]; then
echo "Pausing, press enter to continue"
read
i=0
fi
((i++))
done
Une autre variation, inspirée de https://unix.stackexchange.com/a/105042/66736 :
cp `ls -d ./* | head -n 100` tmpi
Ce n'est peut-être pas le moyen le plus rapide ou le plus élégant, mais c'est un moyen que vous pouvez garder en mémoire.