Як перемістити 100 файлів із папки, що містить тисячі?


43

У мене каталог з тисячами файлів. Як я можу перемістити 100 файлів (будь-які файли) в інше місце.


Оскільки у Unix та Linux немає одного великого веб-сайту про його інструменти, тому я просто переходжу на веб-сайт, як about.comі на якийсь інший веб-сайт, для переліку доступних варіантів, які я можу використати .. але не знайшов нічого подібногоtail
gaijin

Відповіді:


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

Це передбачає , що імена файлів не містять прогалини, символи нового рядка (передбачається , що значення за замовчуванням $IFS), групові символи ( ?, *, [) або почати з -.


12
Зауважте, що цей підхід працює лише в тому випадку, якщо в іменах файлів немає спеціальних символів (пробіли, символи, що не друкуються, ``). Як правило, не розбирайте результатls . І завжди подвійне цитування параметрів і підстановок команд.
Жил 'ТАК - перестань бути злим'

1
На яку частину припадає 100 файлів?
тшепанг

3
Оновлення до мого попереднього коментаря: Прочитавши посилання Gilles, не розбирайте висновок ls , я виявив, що моєї findкоманди бракувало. Аргумент був у неправильному місці, і я додав нульові закінчення імен файлів. Це трохи довгий один рядок, але це все, що я можу зробити в коментарі. Ось фіксований фрагмент:find . -maxdepth 1 -type f \( ! -iname ".*" \) -print0 | while read -rd $'\0' file ; do mv -- "$file" /other/location/ ; done
Пітер.O

@perer Так само, як зауваження, що read -dопція не є портативною для всіх оболонок, але якщо ви все одно використовуєте bash, -d ''має отримати такий же ефект, як і -d $'\0'.
jw013

FWIW, якщо ви хочете, щоб це працювало як лінійку, додайте ;туди, де зараз є новий рядок.
Патрік

37

Найпростіше в zsh:

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

Це переміщує перші 100 не прихованих файлів (будь-якого типу, зміни ([1,100])на лише (.[1,100])для звичайних файлів або (^/[1,100])для будь-якого типу, крім каталогу ) у лексикографічному порядку. Ви можете вибрати інший порядок сортування за допомогою o класифікатора глобуса , наприклад, для переміщення 100 найстаріших файлів:

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

З іншими оболонками ви можете це зробити в петлі з раннього виходу.

i=0
for x in *; do
  if [ "$i" = 100 ]; then break; fi
  mv -- "$x" /other/location/
  i=$((i+1))
done

Іншим портативним способом було б скласти список файлів та видалити всі, крім останніх 100 .


+1 для безпечного розширення оболонки. Буде також легше читатись із збільшенням операції $(( i++ ))чи $[ i++ ]?

2
@hesse Деякі оболонки не реалізуються ++та --. Ви можете писати : $((i+=1))замість i=$((i+1)); Я не переконаний, що це читабельніше.
Жиль "ТАК - перестань бути злим"

1
:-D, я фактично відредагував цю відповідь, думаючи, що це моя ... Вибачте. Сміливо повертайтеся, оскільки це змінює значення.
Стефан Шазелас

@ StéphaneChazelas Мені цікаво, чому ви виключали каталоги та посилання, питання не говорило про це.
Жил 'ТАК - перестань бути злим'

@Gilles, прийнята відповідь ls -p | grep -v /так має нещодавнє запитання, яке тут проходить.
Стефан Шазелас

8

Якщо ви не використовуєте zsh:

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

Перенесуть останні (в алфавітному порядку) 100 одиниць.


3

Наступний oneliner в оболонці допоможе.

foreach i (`знайти Source_Directory -тип f - max-глибина 1 | хвіст -100`); робити; {mv $ i Target_Directory}; зроблено

1
Що це за оболонка?
phk

@phk, це могло б спрацювати, zshнавіть якщо з першого погляду це виглядає зовсім чуже zshсинтаксису. Жиль показав набагато простіший спосіб зробити це zsh. Навіть тоді це все-таки достовірніше, ніж прийнята на даний момент відповідь.
Стефан Шазелас

3

Наступне працювало для мене. Вибачте, якщо вона була розміщена раніше, але я її не побачив у швидкому скануванні.

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


1

mmv - видатна утиліта, яка також дозволить зробити масове перейменування файлів. (Мені довелося sudo apt-get install mmvвстановити його на комп’ютер.) Простий приклад використання: припустимо, у вас є каталог файлів із розширенням .JPG, який ви хочете змінити на малий .jpg. Наступна команда виконує трюк:

mmv \*.JPG \#1.jpg

Зворотна косою рисою використовується для того, щоб відображати підстановку підказки. * / JPG відповідає будь-чому з розширенням JPG. У частині команди "до" команда №1 використовує відповідний текст з першого підстановочного символу для перейменування файлу. Звичайно, ви можете поставити інший шлях до №1, щоб також перемістити файл.


2
Було б вигідніше, якби ви вказали, як би ви насправді використовували запропонований вами інструмент для досягнення мети.
Дасон

1
додав приклад використання
Піт

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

спробуйте цей код


0

Спробуйте це:

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

Це неправильно, ви передаєте три аргументи mv, останній з яких (ймовірно) не є каталогом. І це насправді не відповідає на запитання - запитувач хоче перемістити задану кількість файлів, не всіх.
Мат

Команда оновлена.
Сауміл

0

Я прийшов сюди, але я був необхідності копіювати файли в частині (99) кожен з /DIR1до /DIR2. Я вставлю сюди сценарій, щоб допомогти otherz, можливо:

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

наступна команда працює, якщо вам цікаво використовувати ls

$ ls -rt source/* | head -n100 | xargs cp -t destination

Як це працює ??

  • ls -rt source/* - команда перераховує всі файли з відносним шляхом
  • head -n100 - бере перші 100 файлів
  • xargs cp -t destination - переміщує ці файли в папку призначення

0

Якщо ви хочете захистити / обробляти імена файлів з пробілами, новинками, котируваннями, косою рисою тощо у них, ви повинні використовувати розділові знаки, що скасовуються з нулем:

find "$srcdir" -maxdepth 1 -type f -print0 | head -z -n 100 | xargs -0 -r -- mv -t "$destdir" --

EDIT2: Примітка: якщо у вас немає head -z( по будь-якої причини ) , ви можете замінити вище head -z -n 1000з tr '\0\n' '\n\0' | head -n 1000 | tr '\0\n' '\n\0'(або побачити інші способи )

-maxdepth 1не вдасться шукати файли у підкаталогах $srcdir, тому єдиними переліченими є файли всередині $srcdir.
-print0буде використовувати \0замість newline ( \n) між кожним переліченим файлом - це допомагає обробляти файли, що містять нові рядки та пробіли, з xargs.
head -zбуде вважати \0закінчені (замість нових рядків ( \n) завершені) рядки як рядки. -n 100відобразить лише перші знайдені 100файли find.
Якщо ви хочете побачити, яка команда xargsбуде виконуватися, додайте -t(або --verbose).
xargs -0"Елементи введення закінчуються \0символом null ( ), а не пробілом, а лапки та зворотна коса риса не є спеціальними (кожен символ приймається буквально)"
xargs -rне запускаєтьсяmvякщо немає файлів для переміщення (тобто, якщо findне знайдено жодних файлів).
--припиняє обробку аргументів як опцій для програми, детальніше тут

Вибірка зразка (виконує одну mvкоманду і також може обробляти файли з новими рядками на їх ім'я):

$ 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'

Для 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.

Для 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: Хтось згадав, що їх не було head -z, це версія, якою я користувався (у 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

Для 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.

Для cp:

-t, --target-directory=DIRECTORY
       copy all SOURCE arguments into DIRECTORY
-v, --verbose
       explain what is being done

-1

Я знаю, що ця тема досить стара, але я знайшов відповіді складнішими, ніж я вважав, що вони повинні бути. Це працювало в CentOS, але здається досить простим, що, ймовірно, має працювати в інших дистрибутивах.

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

1
Це не працює, оскільки вихідний файл lsне буде містити провідний somedir/префікс, і не буде працювати для імені файлів із порожніми або символами підстановки чи починати з -.
Stéphane Chazelas

Досить справедливо. Я насправді зробив cp ls | head -n 100../someDir100/ зсередини цільового каталогу, і жодне з назв файлів не задовольняло ці випадки. Краще пощастить, тоді добрий!
Джейсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.