बैश के साथ बड़ी संख्या में छवि फ़ाइलों का नामकरण


16

मुझे लगभग नाम बदलने की आवश्यकता है। 70,000 फाइलें। उदाहरण के लिए: आदि sb_606_HBO_DPM_0089000से sb_606_dpm_0089000

संख्या सीमा से जाता 0089000है 0163022। यह केवल नाम का पहला भाग है जिसे बदलने की आवश्यकता है। सभी फाइलें एकल निर्देशिका में हैं, और क्रमिक रूप से (एक छवि अनुक्रम) क्रमांकित हैं। संख्या अपरिवर्तित रहना चाहिए।

जब मैं इसे कोसने की कोशिश करता हूं तो मुझ पर यह आरोप लगता है कि 'तर्क सूची बहुत लंबी है'।

संपादित करें:

मैंने पहली बार एक फ़ाइल का नाम बदलने की कोशिश की mv:

mv sb_606_HBO_DPM_0089000.dpx sb_606_dpm_0089000.dpx

फिर मैंने एक श्रेणी का नाम बदलने की कोशिश की (मैंने पिछले सप्ताह यहां सीखा कि फाइलों का भार कैसे उठाया जाए, इसलिए मुझे लगा कि फाइलों को बदलने के लिए एक ही वाक्यविन्यास काम कर सकता है ...)। मुझे लगता है कि मैंने निम्नलिखित की कोशिश की (या ऐसा कुछ):

mv sb_606_HBO_DPM_0{089000..163023}.dpx sb_606_dpm_0{089000..163023}.dpx

4
समीक्षकों के लिए : मुझे नहीं लगता कि यह कोई डुप्लिकेट है; शेल की ARG_MAXसीमा के साथ बड़ी संख्या में फाइल टकराने के कारण अन्य प्रश्नों पर अधिकांश CLI उत्तर यहां काम नहीं करेंगे । जैसा कि यह प्रश्न स्पष्ट रूप से कमांड-लाइन समाधान के लिए पूछता है, (संभवतः बराबर) जीयूआई समाधान जैसा कि अन्य प्रश्न में भी मेल नहीं खाता है।
मिठाई

1
मुझे नहीं लगता कि यह एक धोखा है क्योंकि फ़ाइलों का नाम बदलने के बारे में एक से अधिक प्रश्न रखना ठीक है। कृपया नहीं की सामान्य संसाधनों के खिलाफ करीब विशिष्ट प्रश्न है कि वास्तव में उन्हें जवाब नहीं ...
Zanna

1
@ आप यदि स्पष्ट रूप से संपादित कर सकते हैं कि आपने क्या कमांड की कोशिश की है, तो यह स्पष्ट हो जाएगा कि यह कोई धोखा नहीं है। (यह हमें दिखाता है कि आप इस दृष्टिकोण से अवगत हैं।) चीयर्स
स्पार्कहॉक

2
धनी, आपका प्रश्न कोई धोखा नहीं है, क्योंकि यह एक विशिष्ट प्रश्न है। उस के बारे में चिंता मत करो। इससे भी महत्वपूर्ण बात यह है कि एक प्रश्न के बाद कई उत्तर प्राप्त हुए हैं, इसे संपादित करना शायद एक अच्छा विचार नहीं है क्योंकि आपके संपादन मौजूदा उत्तरों को कम वैध बना सकते हैं। अब मुझे ऐसा लग रहा है कि मेरे उत्तर में यह बताया जाना चाहिए कि mv {1..2} {3..4}काम क्यों नहीं होता है, जो कि पूरी तरह से अलग समस्या है ARG_MAX... बाकी सभी जिन्होंने उत्तर दिया है, वे शायद ऐसा ही महसूस करेंगे! इसलिए, मेरे दृष्टिकोण से, मैं चाहता हूं कि आप अपना अंतिम संपादन रोलबैक करें और, यदि आप चाहते हैं, तो mvरेंज के साथ आईएनजी के बारे में एक नया सवाल पूछें
ज़न्ना

1
@ शेपहर्क ओपी ने प्रश्न के पहले संस्करण से स्पष्ट रूप से लिखा, कि समस्या argument list too longत्रुटि है। आगे स्पष्ट करने की आवश्यकता नहीं है, यह स्पष्ट रूप से एक धोखा नहीं है क्योंकि हमें ARG_MAX से निपटने के लिए वर्कअराउंड की आवश्यकता है और प्रस्तावित डुप्लिकेट में उत्तर ऐसा नहीं करते हैं।
टेराडॉन

जवाबों:


25

एक तरीका है , और विकल्प के findसाथ उपयोग करना है। यह एक तर्क सूची का निर्माण करता है, लेकिन अधिकतम तर्क सूची को पार किए बिना सभी फ़ाइलों पर कार्य करने के लिए आवश्यक कॉल के रूप में सूची को तोड़ता है। यह उपयुक्त है जब सभी तर्कों को समान माना जाएगा। यह मामला है , हालांकि नहीं ।-exec+renamemv

आपको पर्ल नाम बदलने की आवश्यकता हो सकती है:

sudo apt install rename

फिर आप उपयोग कर सकते हैं, उदाहरण के लिए:

find . -maxdepth 1 -exec rename -n 's/_HBO_DPM_/_dpm_/' {} +

-nपरीक्षण के बाद निकालें , वास्तव में फ़ाइलों का नाम बदलें।


11

मैं तीन विकल्प सुझाने जा रहा हूं। प्रत्येक एक सरल सिंगल लाइन कमांड है, लेकिन मैं अधिक जटिल मामलों के लिए वेरिएंट प्रदान करूंगा, मुख्य रूप से मामले में प्रोसेस करने के लिए फाइलें उसी निर्देश में अन्य फाइलों के साथ मिश्रित होती हैं।

mmv

मैं उसी नाम के पैकेज से mmv कमांड का उपयोग करूंगा :

mmv '*HBO_DPM*' '#1dpm#2'

ध्यान दें कि तर्क तार के रूप में पारित किए जाते हैं, इसलिए गोला विस्तार शेल में नहीं होता है। कमांड वास्तव में दो तर्कों को प्राप्त करता है, और फिर फ़ाइलों की संख्या पर तंग सीमा के बिना आंतरिक रूप से संबंधित फ़ाइलों को पाता है। यह भी ध्यान दें कि ऊपर दी गई कमांड मानती है कि पहली ग्लोब से मेल खाने वाली सभी फाइलों का नाम बदल दिया जाएगा। बेशक आप अधिक विशिष्ट होने के लिए स्वतंत्र हैं:

mmv 'sb_606_HBO_DPM_*' 'sb_606_dpm_#1'

यदि आपके पास एक ही निर्देशिका में अनुरोधित संख्या सीमा के बाहर की फाइलें हैं, तो आप इस उत्तर में और नीचे दिए गए संख्याओं के लूप से बेहतर हो सकते हैं। हालाँकि आप उपयुक्त पैटर्न के साथ mmv इनवोकेशन के अनुक्रम का भी उपयोग कर सकते हैं:

mmv 'sb_606_HBO_DPM_0089*'       'sb_606_dpm_0089#1'    # 0089000-0089999
mmv 'sb_606_HBO_DPM_009*'        'sb_606_dpm_009#1'     # 0090000-0099999
mmv 'sb_606_HBO_DPM_01[0-5]*'    'sb_606_dpm_01#1#2'    # 0100000-0159999
mmv 'sb_606_HBO_DPM_016[0-2]*'   'sb_606_dpm_016#1#2'   # 0160000-0162999
mmv 'sb_606_HBO_DPM_01630[01]?'  'sb_606_dpm_01630#1#2' # 0163000-0163019
mmv 'sb_606_HBO_DPM_016302[0-2]' 'sb_606_dpm_016302#1'  # 0163020-0163022

संख्या पर लूप

यदि आप कुछ भी स्थापित करने से बचना चाहते हैं, या इस सीमा के बाहर मैच से बचने के लिए नंबर रेंज द्वारा चयन करने की आवश्यकता है, और आप 74,023 कमांड इनवोकेशन की प्रतीक्षा करने के लिए तैयार हैं, तो आप एक सादे बैश लूप का उपयोग कर सकते हैं:

for i in {0089000..0163022}; do mv sb_606_HBO_DPM_$i sb_606_dpm_$i; done

यह विशेष रूप से अच्छी तरह से यहाँ काम करता है क्योंकि अनुक्रम में कोई अंतराल नहीं हैं। अन्यथा आप जांच सकते हैं कि स्रोत फ़ाइल वास्तव में मौजूद है या नहीं।

for i in {0089000..0163022}; do
  test -e sb_606_HBO_DPM_$i && mv sb_606_HBO_DPM_$i sb_606_dpm_$i
done

ध्यान दें कि for ((i=89000; i<=163022; ++i))ब्रेस विस्तार के विपरीत कुछ साल पहले कुछ बैश रिलीज होने के बाद से अग्रणी शून्य को संभालता है। वास्तव में एक परिवर्तन जिसका मैंने अनुरोध किया था, इसलिए मैं इसके लिए उपयोग के मामलों को देखकर खुश हूं।

आगे पढ़ने: बैश जानकारी पृष्ठों में ब्रेस विस्तार , विशेष रूप से के बारे में हिस्सा {x..y[..incr]}

फाइलों पर लूप

एक अन्य विकल्प एक उपयुक्त ग्लोब पर लूप करना होगा, इसके बजाय प्रश्न में पूर्णांक सीमा पर लूपिंग के बजाय। कुछ इस तरह:

for i in *HBO_DPM*; do mv "$i" "${i/HBO_DPM/dpm}"; done

फिर से यह mvप्रति फ़ाइल एक मंगलाचरण है। और फिर से लूप तत्वों की एक लंबी सूची से अधिक है, लेकिन पूरी सूची को एक उपप्रकार के तर्क के रूप में पारित नहीं किया गया है, लेकिन आंतरिक रूप से बैश द्वारा संभाला जाता है, इसलिए यह सीमा आपको समस्याओं का कारण नहीं बनेगी।

आगे पढ़ना: बैश जानकारी पृष्ठों में शेल पैरामीटर विस्तार , ${parameter/pattern/string}दूसरों के बीच दस्तावेजीकरण ।

यदि आप अपने द्वारा प्रदत्त संख्या सीमा को सीमित करना चाहते हैं, तो आप उसके लिए एक चेक जोड़ सकते हैं:

for i in sb_606_HBO_DPM_+([0-9]); do
  if [[ "${i##*_*(0)}" -ge 89000 ]] && [[ "${i##*_*(0)}" -le 163022 ]]; then
    mv "$i" "${i/HBO_DPM/dpm}"
  fi
done

यहाँ ${i##pattern}से सबसे लंबे उपसर्ग को हटाता patternहै $i। उस सबसे लंबे उपसर्ग को कुछ के रूप में परिभाषित किया जाता है, फिर एक अंडरस्कोर, फिर शून्य या अधिक शून्य। उत्तरार्द्ध को लिखा गया है, *(0)जो एक विस्तारित ग्लोब पैटर्न है जो सेट किए जा रहे extglobविकल्प पर निर्भर करता है । प्रमुख शून्य को हटाना संख्या 10 को आधार मान लेना महत्वपूर्ण है। आधार 8. +([0-9])लूप तर्क में एक और विस्तारित ग्लोब है, जो एक या एक से अधिक अंकों से मेल खाता है, बस आपके पास वहीं फाइलें हैं जो शुरू होती हैं लेकिन अंत में समाप्त नहीं होती हैं नंबर।


धन्यवाद! यह एक सपने की तरह काम करता है: i के लिए {0089000..0163022} में; do mv sb_606_HBO_DPM_ $ i sb_606_dpm_ $ i; किया गया - मुझे इसे काम करने के लिए फ़ाइल नाम एक्सटेंशन को जोड़ना पड़ा, लेकिन यह सिर्फ वही हुआ जो मैं चाहता था और मुझे सिंटैक्स भी समझ में आया। थैंक्यू @MvG
अमीर

@rich: खुश मैं मदद कर सकता है - आप और उम्मीद है कि भविष्य के आगंतुकों के रूप में अच्छी तरह से। सबसे उपयोगी उत्तर को स्वीकार करना न भूलें । यदि आप कुछ बेहतर करते हैं तो आप भविष्य में हमेशा उस चेक मार्क को बदल सकते हैं।
एमवीजी

10

ARG_MAXसीमा के चारों ओर काम करने का एक तरीका बैश शेल के बिलिन का उपयोग करना है printf:

printf '%s\0' sb_* | xargs -0 rename -n 's/HBO_DPM/dpm/'

पूर्व।

rename -n 's/HBO_DPM/dpm/' sb_*
bash: /usr/bin/rename: Argument list too long

परंतु

printf '%s\0' sb_* | xargs -0 rename -n 's/HBO_DPM/dpm/'
rename(sb_606_HBO_DPM_0089000, sb_606_dpm_0089000)
.
.
.
rename(sb_606_HBO_DPM_0163022, sb_606_dpm_0163022)

7
find . -type f -exec bash -c 'echo $1 ${1/HBO_DPM/dpm}' _ {} \;
./sb_606_HBO_DPM_0089000 ./sb_606_dpm_0089000

findमौजूदा निर्देशिका में .सभी फ़ाइलों के लिए -type fऔर फ़ाइल का नाम बदलें कर पाया $1की जगह के साथ HBO_DPMसाथ dmp एक के बाद एक-exec ... \;

नाम बदलने के echoसाथ mvबदलें।


6

आप थोड़ा अजगर स्क्रिप्ट लिख सकते हैं, कुछ इस तरह:

import os
for file in os.listdir("."):
    os.rename(file, file.replace("HBO_DPM", "dpm"))

उस पाठ फ़ाइल के रूप rename.pyमें सहेजें जैसे फ़ोल्डर में फ़ाइलें हैं, फिर उस फ़ोल्डर में टर्मिनल के साथ जाएं:

python rename.py

6

आप इसे फ़ाइल द्वारा फ़ाइल कर सकते हैं (इसमें कुछ समय लग सकता है)

sudo apt install util-linux  # if you don't have it already
for i in *; do rename.ul HBO_DPM dpm "$i"; done

renameअन्य उत्तरों में प्रयुक्त पर्ल की तरह , rename.ulएक विकल्प -nया --no-actपरीक्षण के लिए भी है ।


मैंने ज़न्ना के उत्तर के बारे में आपकी टिप्पणी को संपादित कर दिया है, कृपया ज़न्ना के उत्तर को संपादित करें या एक टिप्पणी छोड़ दें।
जीवाश्म

@ubashu जो मेरे उत्तर पर कोई टिप्पणी नहीं थी - यह उस -nझंडे की बात कर रहा था जिसका उपयोग मैंने परीक्षण और सुझाव के लिए किया था, का उपयोग rename.ulभी किया जा सकता है।
ज़न्ना

3

मैं देखता हूं कि किसी ने मेरे सबसे अच्छे दोस्त sedको पार्टी में आमंत्रित नहीं किया :)। निम्नलिखित forलूप आपके लक्ष्य को पूरा करेगा:

for i in sb_606_HBO_DPM*; do
  mv "$i" "$(echo $i | sed 's/HBO_DPM/dpm/')";
done

ऐसी नौकरी के लिए कई उपकरण हैं, वह चुनें जो आपके लिए सबसे अधिक समझ में आता है। यह एक सरल और आसानी से इस या अन्य उद्देश्यों के अनुरूप है ...


दी गई, इस विशिष्ट मामले में बहुत प्रासंगिक नहीं है, लेकिन यह विफल हो जाएगा यदि फ़ाइल के किसी भी नाम में नई सुर्खियाँ हों। मैं इसका उल्लेख सबसे अधिक (सभी?) अन्य उत्तरों को मजबूत करता हूं और मनमाने ढंग से फाइल नामों से निपट सकता हूं, या केवल ओपी की फाइल नामकरण योजना पर काम कर सकता हूं ।
टेराडन

... newlines, रिक्त स्थान, वाइल्डकार्ड, ... जिनमें से कुछ $iको कमांड प्रतिस्थापन में उद्धृत करके बचा जा सकता है , लेकिन फ़ाइल नाम में अनुगामी न्यूलाइन को संभालने का कोई आसान तरीका नहीं है।
'12

3

चूंकि हम विकल्प दे रहे हैं, यहाँ एक पर्ल दृष्टिकोण है। cdलक्ष्य निर्देशिका में और दौड़ें:

perl -e 'foreach(glob("sb_*")){rename $_, s/_HBO_DPM_/_dpm_/r}'

व्याख्या

  • perl -e: द्वारा दी गई स्क्रिप्ट को चलाएं -e
  • foreach(glob){}: { }ग्लोब के प्रत्येक परिणाम पर जो कुछ भी है उसे चलाएं ।
  • glob("sb_*"): वर्तमान निर्देशिका में उन सभी फाइलों और निर्देशिकाओं की सूची लौटाएं जिनके नाम शेल ग्लोब से मेल खाते हैं sb*
  • rename $_, s/_HBO_DPM_/_dpm_/r: पर्ल मैजिक। $_एक विशेष चर है जो प्रत्येक तत्व को रखता है जिसे हम (में foreach) से अधिक पुनरावृत्त कर रहे हैं । तो यहाँ, यह प्रत्येक फ़ाइल मिलेगी। s/_HBO_DPM_/_dpm_/के _HBO_DPM_साथ पहली घटना को प्रतिस्थापित करता है _dpm_। यह $_डिफ़ॉल्ट रूप से चलता है , इसलिए यह प्रत्येक फ़ाइल नाम पर चलेगा। इसका /rमतलब है "इस प्रतिस्थापन को लक्ष्य स्ट्रिंग (फ़ाइल नाम) की एक प्रति पर लागू करें और संशोधित स्ट्रिंग लौटाएँ। renameवह वही करेगा जो आप अपेक्षा करेंगे: यह फ़ाइलों का नाम बदल देता है। इसलिए पूरी चीज़ वर्तमान फ़ाइल नाम ( $_) को स्वयं के साथ बदल देगी।" _HBO_DPM_द्वारा प्रतिस्थापित किया गया _dpm_

आप एक विस्तारित (और अधिक पठनीय स्क्रिप्ट) के रूप में एक ही बात लिख सकते हैं:

#! /usr/bin/env perl
use strict;
use warnings;

foreach my $fileName (glob("sb_*")){
  ## Copy the name to a new variable
  my $newName = $fileName;
  ## change the copy. $newName is now the changed version
  $newName =~ s/_HBO_DPM_/_dpm_/;
  ## rename
  rename $fileName, $newName;
}

1

नाम बदलने के प्रकार पर निर्भर करते हुए, आप कई पंक्तियों के संपादन के साथ विदिर का उपयोग कर संतोषजनक हो सकते हैं।
आपके विशेष मामले में आप अपने टेक्स्ट एडिटर में सभी पंक्तियों का चयन कर सकते हैं और कुछ कीस्ट्रोक्स में फ़ाइलनामों के _ " HBO" भाग को हटा सकते हैं ।


हाँ, vi में खोजने योग्य और बदलने योग्य है।
जैसन

2
क्या आप अपना जवाब बढ़ा सकते हैं और एक उदाहरण दे सकते हैं कि ओपी के लक्ष्य को कैसे प्राप्त किया जाए vidir?
मिठाई
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.