จะย้ายไฟล์ 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และใช้พารามิเตอร์ double-quote และการแทนที่คำสั่งเสมอ
Gilles 'หยุดความชั่วร้าย' ใน

1
ส่วนใดที่มีไฟล์ 100 ไฟล์
tshepang

3
อัปเดตเป็นความคิดเห็นก่อนหน้าของฉัน: หลังจากอ่านลิงก์อ้างอิงของ Gilles อย่าแยกเอาต์พุตของ lsฉันพบว่าfindคำสั่งของฉันขาด หาเรื่องอยู่ผิดที่และฉันได้เพิ่มชื่อตอนท้ายชื่อไฟล์ว่างไว้ มันยาวไปหน่อยสำหรับบรรทัดเดียว แต่นั่นคือทั้งหมดที่ฉันสามารถทำได้ในความคิดเห็น นี่คือตัวอย่างข้อมูลที่แก้ไขแล้ว:find . -maxdepth 1 -type f \( ! -iname ".*" \) -print0 | while read -rd $'\0' file ; do mv -- "$file" /other/location/ ; done
Peter.O

@perer เช่นเดียวกับที่ทราบว่าread -dตัวเลือกนั้นไม่สามารถพกพาไปได้ในทุกเชลล์ แต่หากคุณใช้bashanyways -d ''ควรได้รับผลเช่นเดียวกับ-d $'\0'คุณ
jw013

FWIW หากคุณต้องการให้สิ่งนี้ทำงานเป็น oneliner ให้เพิ่ม;ที่แต่ละบรรทัดใหม่ตอนนี้
Patrick

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)); ฉันไม่เชื่อว่ามันอ่านง่ายขึ้น
Gilles 'หยุดชั่วร้าย'

1
:-D ฉันจริง ๆ แก้ไขคำตอบนี้คิดว่ามันเป็นของฉัน ... ขออภัย อย่าลังเลที่จะเปลี่ยนกลับซึ่งเป็นการเปลี่ยนแปลงความหมาย
Stéphane Chazelas

@ StéphaneChazelasฉันสงสัยว่าทำไมคุณไม่รวมไดเรกทอรีและ symlink คำถามที่พูดอะไรเกี่ยวกับที่
Gilles 'หยุดชั่วร้าย'

@Gilles คำตอบที่ได้รับการยอมรับมีls -p | grep -v /คำถามเมื่อไม่นานมานี้
Stéphane Chazelas

8

หากคุณไม่ได้ใช้ zsh:

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

จะย้ายสุดท้าย (ตามลำดับตัวอักษร) 100 รายการ


3

oneliner ต่อไปนี้ในเปลือกจะช่วย

foreach i (`หา Source_Directory -type f - max-depth 1 | tail -100`); ทำ; {mv $ i Target_Directory}; เสร็จแล้ว

1
เปลือกนั่นคืออะไร?
phk

@phk ที่จะเกิดขึ้นในการทำงานzshแม้ในตอนแรกที่ดูเหมือนว่าคนต่างด้าวค่อนข้างzshไวยากรณ์ Gilles ได้แสดงวิธีที่ง่ายกว่าในการทำสิ่งต่อไปzshนี้ ถึงอย่างนั้นก็ยังเชื่อถือได้มากกว่าคำตอบที่ยอมรับในปัจจุบัน
Stéphane Chazelas

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
มันจะมีประโยชน์มากขึ้นถ้าคุณให้วิธีที่คุณใช้เครื่องมือที่คุณแนะนำเพื่อให้บรรลุเป้าหมาย
Dason

1
เพิ่มตัวอย่างการใช้งาน
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

ลองรหัสนี้


0

ลองสิ่งนี้:

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

สิ่งนี้ไม่ถูกต้องคุณจะผ่านการโต้แย้งสามmvครั้งสุดท้ายซึ่งอาจจะไม่ใช่ไดเรกทอรี และมันไม่ได้ตอบคำถามจริงๆ - ผู้ถามต้องการย้ายไฟล์ตามจำนวนที่กำหนดไม่ใช่ทั้งหมด
จ้า

อัปเดตคำสั่งแล้ว
Saumil

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

หากคุณต้องการที่จะปลอดภัย / จัดการชื่อไฟล์ด้วยช่องว่าง, การขึ้นบรรทัดใหม่, เครื่องหมายคำพูด, แบ็กสแลช ฯลฯ ในนั้นคุณจะต้องใช้ตัวคั่นที่สิ้นสุดด้วยค่า null:

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

แก้ไข 2: หมายเหตุ:หากคุณไม่มีhead -z( ไม่ว่าจะด้วยเหตุผลใด ) คุณสามารถแทนที่ข้างต้นhead -z -n 1000ด้วยtr '\0\n' '\n\0' | head -n 1000 | tr '\0\n' '\n\0'(หรือดูวิธีอื่น ๆ )

-maxdepth 1จะหลีกเลี่ยงการมองหาไฟล์ในไดเรกทอรีย่อยของดังนั้นคนเดียวที่ระบุไว้เป็นไฟล์ภายใน$srcdir จะใช้แทนการขึ้นบรรทัดใหม่ ( ) ระหว่างแต่ละไฟล์ที่แสดงรายการ - สิ่งนี้จะช่วยจัดการไฟล์ที่มีการขึ้นบรรทัดใหม่และช่องว่างด้วย xargs จะนับการสิ้นสุด (แทนการขึ้นบรรทัดใหม่ ( ) สิ้นสุด) เป็นบรรทัด จะแสดงเฉพาะไฟล์แรกที่พบ หากคุณต้องการดูคำสั่งที่จะดำเนินการให้เพิ่ม(หรือ) รายการ "ป้อนข้อมูลจะถูกยกเลิกโดย null ( ) ตัวละครแทนโดยช่องว่างและราคาและทับขวาจะไม่พิเศษ (ตัวละครทุกตัวจะถูกนำตัวอักษร)" จะไม่ทำงาน$srcdir
-print0\0\n
head -z\0\n-n 100100find
xargs-t--verbose
xargs -0\0
xargs -rmvหากไม่มีไฟล์ที่จะย้าย (เช่นหาก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

แก้ไข: มีคนพูดว่าพวกเขาไม่มี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/ จากข้างในไดเรกทอรีเป้าหมายและไม่มีชื่อไฟล์ที่ตรงกับกรณีเหล่านั้น ดีกว่าที่จะเป็นโชคดีแล้วดี!
Jason
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.