سؤال

كيف يمكن لـ Bash إعادة تسمية سلسلة من الحزم لإزالة أرقام إصداراتها؟لقد كنت ألعب مع كليهما expr و %%, ، ولكن دون جدوى.

أمثلة:

Xft2-2.1.13.pkg يصبح Xft2.pkg

jasper-1.900.1.pkg يصبح jasper.pkg

xorg-libXrandr-1.2.3.pkg يصبح xorg-libXrandr.pkg

هل كانت مفيدة؟

المحلول

هل يمكن استخدام المعلمة ميزة التوسع باش

for i in ./*.pkg ; do mv "$i" "${i/-[0-9.]*.pkg/.pkg}" ; done
وهناك حاجة

ونقلت عن أسماء بمسافات.

نصائح أخرى

وإذا كان كل الملفات في نفس الدليل تسلسل

ls | 
sed -n 's/\(.*\)\(-[0-9.]*\.pkg\)/mv "\1\2" "\1.pkg"/p' | 
sh

وسوف القيام بعملك. و<م> ااا الأمر سيخلق سلسلة من ام الأوامر، والتي يمكن بعد ذلك الأنابيب في وعاء. فمن الأفضل لتشغيل أول خط أنابيب دون | sh زائدة وذلك للتحقق من أن الأمر لا ما تريد.

لعنة من خلال الدلائل متعددة استخدام شيء من هذا القبيل

find . -type f |
sed -n 's/\(.*\)\(-[0-9.]*\.pkg\)/mv "\1\2" "\1.pkg"/p' |
sh

لاحظ أنه في ااا التعبير العادي تجميع التسلسل بين قوسين يسبقه مائل، \( و\)، بدلا من الأقواس واحدة ( و).

وسأفعل شيئا من هذا القبيل:

for file in *.pkg ; do
    mv $file $(echo $file | rev | cut -f2- -d- | rev).pkg
done

ويفترض كل ما تبذلونه من الملفات الموجودة في الدليل الحالي. إن لم يكن، في محاولة لاستخدام تجد كما نصحت فوق خافيير.

تعديل : ل. أيضا، وهذه الصيغة لا تستخدم أي ميزات باش معين، كما فعل آخرون أعلاه، الذي يؤدي إلى مزيد من قابلية

وهنا هو POSIX شبه يعادل المقبولة حاليا الجواب . هذا الحرف الوحيد باش التوسع المعلمة ${variable/substring/replacement} واحد والذي يتوفر في أي قذيفة بورن المتوافقة.

for i in ./*.pkg; do
    mv "$i" "${i%-[0-9.]*.pkg}.pkg"
done

وو${variable%pattern} التوسع المعلمة تنتج قيمة variable مع أي لاحقة والذي يطابق pattern إزالتها. (هناك ${variable#pattern} أيضا لإزالة بادئة).

وظللت -[0-9.]* subpattern من الإجابة مقبولة على الرغم من أنه ربما مضللة. انها ليست تعبير عادي، ولكن نمط غلوب. لذلك لا يعني "اندفاعة يليه صفر أو أكثر من أرقام أو النقاط". بدلا من ذلك، وهو ما يعني "اندفاعة، متبوعا برقم أو نقطة، تليها أي شيء". و"أي شيء" ستكون أقصر مباراة الممكنة، وليس أطول. (باش يقدم ## و%% لتقليم أطول بادئة المحتملة أو لاحقة، بدلا من أقصر).

وأفضل استخدام sed لهذا، شيء من هذا القبيل:

find . -type f -name "*.pkg" |
 sed -e 's/((.*)-[0-9.]*\.pkg)/\1 \2.pkg/g' |
 while read nameA nameB; do
    mv $nameA $nameB;
 done

وكشف عن التعبير العادي ويترك باعتبارها ممارسة (كما هو التعامل مع أسماء الملفات التي تتضمن مسافات)

يمكننا أن نفترض sed متوفر على أي *nix ، لكن لا يمكننا التأكد من دعمه sed -n لتوليد أوامر mv.(ملحوظة: جنو فقط sed يفعل هذا.)

ومع ذلك، يمكننا بسرعة إنشاء وظيفة الصدفة للقيام بذلك، باستخدام bash buildins وsed.

sedrename() {
  if [ $# -gt 1 ]; then
    sed_pattern=$1
    shift
    for file in $(ls $@); do
      mv -v "$file" "$(sed $sed_pattern <<< $file)"
    done
  else
    echo "usage: $0 sed_pattern files..."
  fi
}

الاستخدام

sedrename 's|\(.*\)\(-[0-9.]*\.pkg\)|\1\2|' *.pkg

before:

./Xft2-2.1.13.pkg
./jasper-1.900.1.pkg
./xorg-libXrandr-1.2.3.pkg

after:

./Xft2.pkg
./jasper.pkg
./xorg-libXrandr.pkg

إنشاء المجلدات المستهدفة:

منذ mv لا ينشئ المجلدات المستهدفة تلقائيًا لا يمكننا استخدام الإصدار الأولي الخاص بنا من sedrename.

إنه تغيير بسيط إلى حد ما، لذا سيكون من الجيد تضمين هذه الميزة:

سنحتاج إلى وظيفة فائدة، abspath (أو المسار المطلق) نظرًا لأن Bash لا يوجد لديه هذا البناء.

abspath () { case "$1" in
               /*)printf "%s\n" "$1";;
               *)printf "%s\n" "$PWD/$1";;
             esac; }

بمجرد أن نتمكن من إنشاء المجلد (المجلد) المستهدف لنمط SED/RENAME الذي يتضمن بنية مجلد جديدة.

سيضمن هذا أننا نعرف أسماء المجلدات المستهدفة لدينا.عندما نعيد تسميته ، سنحتاج إلى استخدامه على اسم الملف الهدف.

# generate the rename target
target="$(sed $sed_pattern <<< $file)"

# Use absolute path of the rename target to make target folder structure
mkdir -p "$(dirname $(abspath $target))"

# finally move the file to the target name/folders
mv -v "$file" "$target"

إليك النص البرمجي الكامل للمجلد ...

sedrename() {
  if [ $# -gt 1 ]; then
    sed_pattern=$1
    shift
    for file in $(ls $@); do
      target="$(sed $sed_pattern <<< $file)"
      mkdir -p "$(dirname $(abspath $target))"
      mv -v "$file" "$target"
    done
  else
    echo "usage: $0 sed_pattern files..."
  fi
}

بالطبع ، لا يزال يعمل عندما لا يكون لدينا مجلدات مستهدفة محددة أيضًا.

إذا أردنا وضع جميع الأغاني في مجلد، ./Beethoven/ نستطيع فعل ذلك:

الاستخدام

sedrename 's|Beethoven - |Beethoven/|g' *.mp3

before:

./Beethoven - Fur Elise.mp3
./Beethoven - Moonlight Sonata.mp3
./Beethoven - Ode to Joy.mp3
./Beethoven - Rage Over the Lost Penny.mp3

after:

./Beethoven/Fur Elise.mp3
./Beethoven/Moonlight Sonata.mp3
./Beethoven/Ode to Joy.mp3
./Beethoven/Rage Over the Lost Penny.mp3

جولة المكافأة...

استخدام هذا البرنامج النصي لنقل الملفات من المجلدات إلى مجلد واحد:

على افتراض أننا أردنا جمع جميع الملفات المتطابقة ، ووضعها في المجلد الحالي ، يمكننا القيام بذلك:

sedrename 's|.*/||' **/*.mp3

before:

./Beethoven/Fur Elise.mp3
./Beethoven/Moonlight Sonata.mp3
./Beethoven/Ode to Joy.mp3
./Beethoven/Rage Over the Lost Penny.mp3

after:

./Beethoven/ # (now empty)
./Fur Elise.mp3
./Moonlight Sonata.mp3
./Ode to Joy.mp3
./Rage Over the Lost Penny.mp3

ملاحظة على أنماط sed regex

تنطبق قواعد نمط SED العادية في هذا البرنامج النصي ، هذه الأنماط ليست PCRE (تعبيرات منتظمة متوافقة مع PERL).يمكن أن يكون لديك بناء جملة تعبير منتظم تم تمديده ، باستخدام أي منهما sed -r أو sed -Eاعتمادا على النظام الأساسي الخاص بك.

انظر متوافق مع POSIX man re_format للحصول على وصف كامل لأنماط regexp الأساسية والممتدة.

وأجد أن إعادة تسمية أداة أكثر وضوحا بكثير لاستخدام لهذا النوع من الشيء. لقد وجدت أنه في البيرة لOSX

وعلى سبيل المثال الخاص بك وأود أن تفعل:

rename 's/\d*?\.\d*?\.\d*?//' *.pkg

ووالصورة "تعني بديلا. النموذج ق / searchPattern / استبدال / files_to_apply. تحتاج إلى استخدام التعابير المنطقية لهذا الذي يأخذ دراسة صغيرة لكنها تستحق الجهد.

يبدو أن هذا يعمل على افتراض ذلك

  • كل شيء ينتهي بـ $pkg
  • يبدأ رقم الإصدار الخاص بك دائمًا بـ "-"

قم بإزالة .pkg، ثم قم بإزالة -..

for x in $(ls); do echo $x $(echo $x | sed 's/\.pkg//g' | sed 's/-.*//g').pkg; done

وكان لي الملفات *.txt متعددة ليتم تسميتها .sql في نفس المجلد. أدناه عملت بالنسبة لي:

for i in \`ls *.txt | awk -F "." '{print $1}'\` ;do mv $i.txt $i.sql; done

وشكرا لك على هذه الأجوبة. كما أتيحت لي نوعا من المشكلة. نقل الملفات .nzb.queued إلى .nzb الملفات. وكان المساحات والعناصر غير المرغوب فيها الأخرى في أسماء الملفات وهذا حل مشكلتي:

find . -type f -name "*.nzb.queued" |
sed -ne "s/^\(\(.*\).nzb.queued\)$/mv -v \"\1\" \"\2.nzb\"/p" |
sh

وهو يقوم على إجابة لديوميديس سبينيليس.

والتعبير المعتاد يخلق مجموعة واحدة لاسم الملف بأكمله، ومجموعة واحدة بالنسبة للجزء قبل .nzb.queued ثم يخلق أمر قذيفة الخطوة. مع السلاسل نقلت. هذا يتجنب أيضا خلق حلقة في شيل لأن هذا ما يحدث بالفعل من خلال الحوار الاقتصادي الاستراتيجي.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top