Comment déplacer 100 fichiers d'un dossier contenant des milliers?


43

J'ai un répertoire avec des milliers de fichiers. Comment puis-je déplacer 100 des fichiers (tous les fichiers feront) à un autre emplacement.


Parce que Unix et Linux DonT ont un grand site de ses outils, donc je simplement aller sur le site comme about.comet un autre site Web pour la liste des options disponibles que je peux éventuellement utiliser .. mais rien trouvé commetail
gaijin

Réponses:


36
for file in $(ls -p | grep -v / | tail -100)
do
mv $file /other/location
done

Cela suppose des noms de fichiers ne contiennent pas de blancs, de nouvelles lignes ( en supposant que la valeur par défaut $IFS), les caractères génériques ( ?, *, [) ou commencer par -.


12
Notez que cette approche ne fonctionne que s'il n'y a pas de caractères spéciaux (espaces, caractères non imprimables, ``) dans les noms de fichiers. En règle générale, n'analysez pas la sortie dels . Et toujours des guillemets doubles de substitutions de paramètres et de commandes.
Gilles 'SO- arrête d'être méchant'

1
Quelle partie représente 100 fichiers?
Tshepang

3
Mise à jour de mon commentaire précédent: Après avoir lu le lien de référence de Gilles, ne pas analyser la sortie de ls , j'ai constaté que ma findcommande manquait. Un argument était au mauvais endroit et j'ai ajouté des terminaisons nulles pour les noms de fichiers. C'est un peu long d'une seule ligne, mais c'est tout ce que je peux faire dans un commentaire. Voici l'extrait corrigé:find . -maxdepth 1 -type f \( ! -iname ".*" \) -print0 | while read -rd $'\0' file ; do mv -- "$file" /other/location/ ; done
Peter.O

@perer Tout comme une note que l' read -doption n'est pas portable pour tous les shells, mais si vous utilisez bashquand même, -d ''devrait vous donner le même effet que -d $'\0'.
Jw013

FWIW si vous voulez que cela fonctionne en tant que doublure, ajoutez un ;emplacement où se trouve maintenant chaque nouvelle ligne.
Patrick

37

C'est plus facile en zsh:

mv -- *([1,100]) /other/location/

Cela déplace le 100 premiers fichiers non cachés (de tout type, changement ([1,100])à (.[1,100])des réguliers uniquement les fichiers ou (^/[1,100])pour tout type mais répertoire ) dans l' ordre lexicographique nom. Vous pouvez sélectionner un ordre de tri différent avec le o qualificatif glob , par exemple pour déplacer les 100 fichiers les plus anciens:

mv -- *(Om[1,100]) /other/location/

Avec d'autres coquillages, 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 méthode portable consiste à créer la liste des fichiers et à supprimer tous les fichiers sauf les 100 derniers .


+1 pour une expansion sécurisée du shell. Serait également plus lisible avec l'opération d'incrémentation $(( i++ ))ou $[ i++ ]?

2
@hesse Certains obus ne sont pas implémentés ++et --. Vous pouvez écrire : $((i+=1))au lieu de i=$((i+1)); Je ne suis pas convaincu que c'est plus lisible.
Gilles, arrête d'être méchant

1
:-D, j'ai en fait modifié cette réponse en pensant que c'était la mienne ... Désolé. N'hésitez pas à revenir car cela change le sens.
Stéphane Chazelas

@ StéphaneChazelas Je me demande pourquoi vous excluez les répertoires et les liens symboliques, la question ne disait rien à ce sujet.
Gilles 'SO- arrête d'être méchant'

@ Gilles, la réponse acceptée a ls -p | grep -v /donc été la question récente qui dupe ici.
Stéphane Chazelas

8

Si vous n'utilisez pas zsh:

set -- *
[ "$#" -le 100 ] || shift "$(($# - 100))"
mv -- "$@" /target/dir

Déplacerait les derniers (dans l'ordre alphabétique) 100.


4

Ce qui suit a fonctionné pour moi. Désolé si cela a été posté précédemment, mais je ne l'ai pas vu dans un scan rapide.

ls path/to/dir/containing/files/* | head -100 | xargs -I{} cp {} /Path/to/new/dir

3

L'oneliner suivant dans la coquille aiderait.

foreach i (`find source_Directory -type f --max-depth 1 | tail -100`); faire; {mv $ i Target_Directory}; terminé

1
C'est quoi cette coquille?
phk

@phk, cela arriverait zshmême si, à première vue, cela semblait assez étranger à la zshsyntaxe. Gilles a montré une manière beaucoup plus simple de le faire zsh. Même dans ce cas, cela reste plus fiable que la réponse actuellement acceptée.
Stéphane Chazelas


1

mmv est un utilitaire exceptionnel qui vous permettra également de renommer en masse des fichiers. (Je devais l’ sudo apt-get install mmvinstaller sur mon ordinateur.) Exemple d’utilisation simple: supposons que vous disposiez d’un répertoire de fichiers avec l’extension .JPG que vous souhaiteriez remplacer par un .jpg en minuscule. 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 à quoi que ce soit avec une extension JPG. Dans la partie "to" de la commande, le n ° 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 n ° 1 pour déplacer également le fichier.


2
Il serait plus avantageux que vous indiquiez comment vous utiliseriez réellement l'outil que vous proposez pour atteindre l'objectif.
Dason

1
ajout d'un exemple d'utilisation
Pete

1
#!/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


1

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/* - commande liste tous les fichiers avec le chemin relatif
  • head -n100 - prend 100 premiers fichiers
  • xargs cp -t destination - déplace ces fichiers dans le dossier de destination

0

Essaye ça:

find /source/directory -type f -maxdepth 1 -print | tail -100 | xargs -J % mv % /other/location/

Ceci est incorrect, vous passez trois arguments à mv, le dernier dont (probablement) n'est pas un répertoire. Et cela ne répond pas vraiment à la question: le demandeur souhaite déplacer un nombre donné de fichiers, pas tous.
Mat

Commande mise à jour.
Saumil

0

Je suis passé par ici, mais j’avais besoin de copier des fichiers en plusieurs parties (99 chacune) de /DIR1à /DIR2. Je vais coller le script ici pour aider otherz 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

0

Si vous voulez être sûr / gérer les noms de fichiers contenant des espaces, des 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: NOTE: si vous n’avez pas head -z( pour une raison quelconque ), vous pouvez remplacer ce qui précède head -z -n 1000par tr '\0\n' '\n\0' | head -n 1000 | tr '\0\n' '\n\0'(ou voir d’autres manières )

-maxdepth 1évitera la recherche de fichiers dans des sous - répertoires $srcdir, de sorte que les seuls répertoriés sont les fichiers dans $srcdir.
-print0utilisera à la \0place de newline ( \n) entre chaque fichier de la liste - ceci aide à gérer les fichiers contenant des nouvelles lignes et des espaces avec xargs.
head -zcomptera les lignes \0terminées (au lieu de celles terminées par newline ( \n)) comme des lignes. -n 100ne listera que les premiers 100fichiers findtrouvés.
Si vous voulez voir quelle commande xargssera exécutée, ajoutez -t(ou --verbose).
xargs -0"Les éléments en entrée se terminent par un caractère null ( \0) au lieu d'un espace, et les guillemets et la barre oblique inverse ne sont pas spéciaux (chaque caractère est pris littéralement)"
xargs -rne sera pas exécutémvs'il n'y a pas de fichiers à déplacer (c'est-à-dire si findaucun fichier n'a été trouvé).
--termine le traitement des arguments en tant qu'options du programme, plus de détails ici

Exemple de sortie (exécute une mvcommande et peut gérer des fichiers avec des nouvelles lignes dans leur nom également):

$ 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 a mentionné qu'ils ne l'avaient pas head -z, c'est 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


-2

Je sais que ce fil est assez ancien, mais j'ai trouvé les réponses plus compliquées que je ne le pensais. Cela a fonctionné dans CentOS, mais cela semble assez simple pour que cela fonctionne probablement dans d’autres distributions.

cp `ls someDir | head -n 100` someDir100/

1
Cela ne fonctionne pas car la sortie de lsne comprendra pas le somedir/préfixe de début et ne fonctionnera pas pour le nom de fichier avec des caractères vierges ou génériques ou pour commencer par -.
Stéphane Chazelas

C'est suffisant. J'ai en fait cp ls | head -n 100../someDir100/ Depuis le répertoire cible et aucun des noms de fichiers ne correspond à ces cas. Mieux vaut avoir de la chance que du bien!
Jason
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.