सबसे छोटी फाइलों को पहले कॉपी करें?


15

मेरे पास एक बड़ी निर्देशिका है जिसमें उपनिर्देशिकाएं और फाइलें हैं जो मैं पुनरावर्ती रूप से कॉपी करना चाहता हूं।

क्या cpयह बताने का कोई तरीका है कि इसे फ़ाइल आकार के क्रम में कॉपी ऑपरेशन करना चाहिए, ताकि सबसे छोटी फ़ाइलों को पहले कॉपी किया जा सके?


1
बस यह सुनिश्चित करने के लिए कि कोई XY समस्या शामिल नहीं है, क्या आप बता सकते हैं कि आप ऐसा क्यों करना चाहते हैं?
गोल्डीलॉक्स

4
@ TAFKA'goldilocks '- मेरे पास बहुत सारी वीडियो फाइलें हैं, और मैं प्रत्येक निर्देशिका का गुणवत्ता परीक्षण करना चाहता हूं। सबसे छोटी वीडियो मुझे एक त्वरित संकेत देगी कि क्या बाकी फाइलें खराब हैं।
nbubis

जवाबों:


10

यह पूरी नौकरी एक ही बार में करता है - सभी बाल निर्देशिकाओं में, बिना किसी फ़ाइल नाम की समस्याओं के सभी एक ही धारा में। यह आपके पास मौजूद हर फ़ाइल में सबसे छोटी से लेकर बड़ी कॉपी होगी। mkdir ${DESTINATION}यदि यह पहले से मौजूद नहीं है तो आपको इसकी आवश्यकता होगी ।

find . ! -type d -print0 |
du -b0 --files0-from=/dev/stdin |
sort -zk1,1n | 
sed -zn 's/^[^0-9]*[0-9]*[^.]*//p' |
tar --hard-dereference --null -T /dev/stdin -cf - |
    tar -C"${DESTINATION}" --same-order -xvf -

तुम्हें पता है क्या, हालांकि? यह क्या नहीं करता है खाली बच्चे निर्देशिका है। मैं उस पाइपलाइन पर कुछ पुनर्निर्देशन कर सकता था, लेकिन यह सिर्फ दौड़ की स्थिति है। सरलतम शायद सबसे अच्छा है। तो बस इसके बाद करें:

find . -type d -printf 'mkdir -p "'"${DESTINATION}"'/%p"\n' |
    . /dev/stdin

या, चूंकि गिल्स निर्देशिका अनुमतियों को संरक्षित करने के लिए अपने जवाब में बहुत अच्छा बिंदु बनाता है, मुझे भी कोशिश करनी चाहिए। मुझे लगता है कि यह ऐसा करेगा:

find . -type d -printf '[ -d "'"${DESTINATION}"'/%p" ] || 
    cp "%p" -t "'"${DESTINATION}"'"\n' |
. /dev/stdin

मैं शर्त लगाने को तैयार हूँ जो mkdirवैसे भी तेज़ है ।


1
लानत है तुम अभागे! +1
गोल्डीलॉक्स

3
@ TAFKA'goldilocks 'मैं इसे एक तारीफ के रूप में लूंगा। बहुत बहुत धन्यवाद।
mikeserv

15

यहां एक त्वरित और गंदे तरीके का उपयोग किया गया है rsync। इस उदाहरण के लिए मैं 10 एमबी से कम "छोटा" होने पर विचार कर रहा हूं।

पहली छोटी फ़ाइलों को स्थानांतरित करें:

rsync -a --max-size=10m srcdir dstdir

फिर बची हुई फाइलों को ट्रांसफर करें। जब तक वे संशोधित नहीं किए गए पहले से स्थानांतरित की गई छोटी फ़ाइलों को फिर से कॉपी नहीं किया जाएगा।

rsync -a srcdir dstdir

से man 1 rsync

   --max-size=SIZE
          This  tells  rsync to avoid transferring any file that is larger
          than the specified SIZE. The SIZE value can be suffixed  with  a
          string  to  indicate  a size multiplier, and may be a fractional
          value (e.g. "--max-size=1.5m").

          This option is a transfer rule, not an exclude,  so  it  doesnt
          affect  the  data  that  goes  into  the file-lists, and thus it
          doesnt affect deletions.  It just limits  the  files  that  the
          receiver requests to be transferred.

          The  suffixes  are  as  follows:  "K"  (or  "KiB") is a kibibyte
          (1024), "M" (or "MiB") is a mebibyte (1024*1024),  and  "G"  (or
          "GiB")  is  a gibibyte (1024*1024*1024).  If you want the multi
          plier to be 1000 instead of  1024,  use  "KB",  "MB",  or  "GB".
          (Note: lower-case is also accepted for all values.)  Finally, if
          the suffix ends in either "+1" or "-1", the value will be offset
          by one byte in the indicated direction.

          Examples:    --max-size=1.5mb-1    is    1499999    bytes,   and
          --max-size=2g+1 is 2147483649 bytes.

बेशक, ट्रांसफर फाइल-बाय-फाइल का आदेश सख्ती से सबसे बड़ा नहीं है, लेकिन मुझे लगता है कि यह सबसे सरल समाधान हो सकता है जो आपकी आवश्यकताओं की भावना को पूरा करता है।


यहां आपको हार्ड-लिंक की 2 प्रतियां मिलती हैं और सॉफ्ट-लिंक प्रत्येक की दो प्रतियों के लिए वास्तविक फाइलों में बदल जाते हैं। आप बहुत अच्छा करेंगे --copy-dest=DIRऔर / या --compare-dest=DIRमुझे लगता है। मुझे केवल इतना पता है कि मुझे अपना उत्तर पोस्ट --hard-dereferenceकरने के tarबाद खुद को जोड़ना पड़ा क्योंकि मुझे लिंक याद आ रहे थे। मुझे लगता है कि rsyncवास्तव में वैसे भी उन लोगों के साथ स्थानीय फाइल सिस्टम के लिए अधिक विशिष्ट व्यवहार होता है - मैं इसे USB कुंजी के साथ उपयोग करता था और जब तक मैं एक बैंडविड्थ सीमा निर्धारित नहीं करता तब तक यह बस को बाढ़ देगा। मुझे लगता है कि मुझे इसके बजाय उन दूसरों का उपयोग करना चाहिए था।
मिकसेर्व

1
"त्वरित और गंदे विधि" के लिए +1। स्वचालन उद्देश्यों और भविष्य की स्थिरता के लिए सरलता कम से कम बेहतर है। मुझे लगता है कि यह वास्तव में बहुत साफ है। "एलिगेंट" बनाम "कुल्डी" और "मजबूत" बनाम "अस्थिर" कभी-कभी डिजाइन लक्ष्यों के रूप में संघर्ष हो सकता है लेकिन एक अच्छा संतुलन है जिसे मारा जा सकता है, और मुझे लगता है कि यह सुरुचिपूर्ण और काफी मजबूत है।
वाइल्डकार्ड

4

cpसीधे तौर पर नहीं , यह अच्छी तरह से अपनी क्षमताओं से परे है। लेकिन आप cpसही क्रम में फाइलों पर कॉल करने की व्यवस्था कर सकते हैं ।

Zsh आसानी से एक ग्लॉब क्वालीफायर के साथ आकार के अनुसार फाइलों को छांटने की अनुमति देता है । यहाँ एक zsh टुकड़ा जो प्रतियां के नीचे से आकार के बढते क्रम में फ़ाइलों है /path/to/source-directoryके तहत करने के लिए /path/to/destination-directory

cd /path/to/source-directory
for x in **/*(.oL); do
  mkdir -p /path/to/destination-directory/$x:h
  cp $x /path/to/destination-directory/$x:h
done

लूप के बजाय, आप zcpफ़ंक्शन का उपयोग कर सकते हैं । हालाँकि आपको पहले गंतव्य निर्देशिकाएँ बनाने की आवश्यकता होती है, जो एक क्रिप्टोकरंसी पर किया जा सकता है।

autoload -U zmv; alias zcp='zmv -C'
cd /path/to/source-directory
mkdir **/*(/e\''REPLY=/path/to/destination-directory/$REPLY'\')
zcp -Q '**/*(.oL)' '/path/to/destination-directory/$f'

यह स्रोत निर्देशिकाओं के स्वामित्व को संरक्षित नहीं करता है। आपको लगता है कि चाहते हैं, आप इस तरह के रूप में एक उपयुक्त नकल कार्यक्रम भर्ती करने की आवश्यकता होगी cpioया pax। आप ऐसा करते हैं, तो आप कॉल करने के लिए की जरूरत नहीं है cpया zcpइसके अलावा में।

cd /path/to/source-directory
print -rN **/*(^.) **/*(.oL) | cpio -0 -p /path/to/destination-directory

2

मुझे नहीं लगता कि cp -rसीधे ऐसा करने का कोई तरीका है । चूँकि यह एक विज़ार्ड find/ awkसमाधान प्राप्त करने से पहले समय की अनिश्चित अवधि हो सकती है , यहाँ एक त्वरित पर्ल स्क्रिप्ट है:

#!/usr/bin/perl
use strict;
use warnings FATAL => qw(all);

use File::Find;
use File::Basename;

die "No (valid) source directory path given.\n"
    if (!$ARGV[0] || !-d -r "/$ARGV[0]");

die "No (valid) destination directory path given.\n"
    if (!$ARGV[1] || !-d -w "/$ARGV[1]");

my $len = length($ARGV[0]);
my @files;
find (
    sub {
        my $fpath = $File::Find::name;
        return if !-r -f $fpath;
        push @files, [
            substr($fpath, $len),
            (stat($fpath))[7],
        ]
    }, $ARGV[0]
);

foreach (sort { $a->[1] <=> $b->[1] } @files) {
    if ($ARGV[2]) {
        print "$_->[1] $ARGV[0]/$_->[0] -> $ARGV[1]/$_->[0]\n";
    } else {
        my $dest = "$ARGV[1]/$_->[0]";
        my $dir = dirname($dest);
        mkdir $dir if !-e $dir;
        `cp -a "$ARGV[0]/$_->[0]" $dest`;
    }
} 
  • इसे इस्तेमाल करो: ./whatever.pl /src/path /dest/path

  • तर्क दोनों पूर्ण मार्ग होने चाहिए ; ~, या कुछ और जो शेल एक निरपेक्ष पथ में फैलता है, ठीक है।

  • यदि आप एक तीसरा तर्क (कुछ भी, शाब्दिक को छोड़कर 0) जोड़ते हैं , तो कॉपी करने के बजाय यह रिपोर्ट की मानक रिपोर्ट को प्रिंट करेगा कि वह क्या करेगा, बाइट्स में फाइल साइज़ के साथ पूर्व निर्धारित है, जैसे।

    4523 /src/path/file.x -> /dest/path/file.x
    12124 /src/path/file.z -> /dest/path/file.z

    सूचना ये आकार के अनुसार बढ़ते क्रम में हैं।

  • cpइसलिए आप जो कुछ स्विच (मैं सिर्फ इस्तेमाल किया साथ चाहते हैं कर सकते हैं लाइन 34 पर आदेश, एक शाब्दिक शेल कमांड है -aसभी लक्षण संरक्षित करने के लिए)।

  • File::Findऔर File::Basenameदोनों मुख्य मॉड्यूल हैं, यानी वे पर्ल के सभी इंस्टॉलेशन में उपलब्ध हैं।


यकीनन, यह यहाँ एकमात्र सही उत्तर है। या यह था ... शीर्षक - बस बदल गया ...? मेरी ब्राउज़र विंडो को कॉल किया जाता है, cp - copy smallest files first?लेकिन पोस्ट का शीर्षक बस copy smallest files first?वैसे भी है, विकल्प कभी भी चोट नहीं पहुंचाते हैं मेरे दर्शन, लेकिन फिर भी, आप और डेविड केवल एक हैं जो उपयोग किए गए हैं cpऔर आप केवल एक हैं जिसने इसे खींच लिया है।
मोकेसर

@mikeserv मेरे द्वारा इस्तेमाल किया जाने वाला एकमात्र कारण cpथा क्योंकि यह (क्रॉस-प्लेटफॉर्म ओरिएंटेड) पर्ल में * निक्स फाइल विशेषताओं को संरक्षित करने का सबसे सरल तरीका है। आपके ब्राउज़र बार के कारण cp - (IMO नासमझ) एसई विशेषता के कारण चयनित टैग्स में से सबसे लोकप्रिय वास्तविक शीर्षक के लिए उपसर्ग दिखाई देता है।
गोल्डीलॉक्स

ठीक है, तो मैं अपनी तारीफ वापस लेता हूं। वास्तव में नहीं, आप अक्सर pearlइधर-उधर लकड़ियों से बाहर आते नहीं दिखते।
मोकेसर

1

एक और विकल्प यह होगा कि डु से आउटपुट के साथ cp का उपयोग करें:

oldIFS=$IFS
IFS=''
for i in $(du -sk *mpg | sort -n | cut -f 2)
do
    cp $i destination
done
IFS=$oldIFS

यह अभी भी एक पंक्ति में किया जा सकता है, लेकिन मैंने इसे विभाजित किया है ताकि आप इसे पढ़ सकें


क्या आपको कम से कम $ IFS के बारे में कुछ करने की आवश्यकता नहीं है?
mikeserv

जी हाँ ... मैं मानता हूँ कि उनके फाइलनाम में किसी की भी नई भूमिका नहीं है
डेविड विल्किंस

1
यह भी ओपी वर्णित निर्देशिका पदानुक्रम के माध्यम से पुनरावृत्ति को संभालने के लिए प्रतीत नहीं होता है।
cpugeniusmv

1
@cpugeniusmv सही ... मैंने किसी तरह पुनरावर्ती भाग को याद किया .... मैं पुनरावृत्ति को संभालने के लिए इसे संशोधित कर सकता था, लेकिन मुझे लगता है कि इस बिंदु पर अन्य उत्तर एक बेहतर काम करते हैं। मैं इसे यहाँ छोड़ दूँगा अगर यह सवाल देखने वाले किसी व्यक्ति की मदद करता है।
डेविड विल्किंस

1
@ डेविडवॉकिन्स - यह बहुत मदद करता है।
nbubis
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.