سؤال كيف أقوم بتنفيذ أوامر في مجلد آخر ، دون تكرار مسار المجلد؟


هل يوجد ذكي طريقة للقيام بنسخ ونقل العمليات أو أمر لتكرار ملف ، دون الحاجة إلى القيام به cd، ثم mv بعد ذلك ، في نفس المجلد؟

على سبيل المثال ، لا بد لي من تشغيل ما يلي:

mv /folder1/folder2/folder3/file.txt /folder1/folder2/folder3/file-2013.txt

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


72
2018-05-17 12:22


الأصل


لا أستطيع أن أصدق أن هذا لديه الكثير من upvotes. انها مكررة unix.stackexchange.com/questions/35782/... و unix.stackexchange.com/questions/66889/... - user13107
@ user13107 هناك العديد من الطرق لطرح سؤال ، بما في ذلك صياغة مختلفة. وإذا كنت لا تعرف أن الإجابة تسمى "توسيع الدعامة" ، فقد لا تتمكن من العثور عليها على الفور. - slhck
@ user13107 هم على موقع مختلف حتى لا تتكرر - Mark
مارك ، شكرًا ، لم أكن أعرف هذه القاعدة حول التكرارات. slhck نعم. أنا أفهم. لقد شعرت بالإحباط لأن سؤالي على Unix.SE قد أغلق على أنه نسخة مكررة ، وقد حظي هذا الأمر بشعبية كبيرة. - user13107
@ user13107 ، هذا ما تحصل عليه للنشر على الموقع الصحيح - Samuel Edwin Ward


الأجوبة:


ببساطة استخدام توسيع الدعامة:

mv /folder1/folder2/folder3/{file.txt,file-2013.txt}

هذا يعادل الكتابة:

mv /folder1/folder2/folder3/file.txt /folder1/folder2/folder3/file-2013.txt

يتيح لك توسع الدعامة تقديم المزيد من الحجج ، بالطبع. يمكنك حتى تمرير النطاقات إليه ، على سبيل المثال ، لإنشاء اثنين من مجلدات الاختبار ، يمكنك تشغيل mkdir test_{a..z}، وبدءًا من Bash 4 ، يمكنك إنشاء تسلسلات غير مبسَّطة كذلك ، كما هو الحال في touch foo{0001..3}مما يخلق foo0001، foo0002 و foo0003. ال باش الهاكرز لديه مقال مع بعض الأمثلة لك.

إذا كان لديك لاستخدام أمرين مختلفين ، استخدم قشرة فرعية و cd هناك أولا ، كما هو الحال في إجابة Ignacio.


124
2018-05-17 12:29



لم أكن أعرف عن brace التوسع ، شكرا لك! - Valter Silva
حاولت ويبدو أنه لا يعمل: meniac ~: mv /tmp/f1/f2/f3/f4/f5/f6/{file.txt, file2.txt} mv: cannot stat ``/tmp/f1/f2/f3/f4/f5/f6/{file.txt,': No such file or directory - Valter Silva
هل أنت متأكد من أنك تستخدم باش ، كما هو الحال في /bin/bash، وأنت لست في البرنامج النصي لديها /bin/sh في shebang أو بعض القشرة الأخرى التي لا تدعم توسيع الدعامة؟ اذا ركضت set، قم بدورك SHELLOPTSيحتوي braceexpand؟ - slhck
لاحظ أنه يجب عدم وجود مسافة بين file.txt, و file2.txt. - slhck
يمكنك جعلها أقصر ، لمنع الأخطاء المطبعية في الجزء الذي لا يتغير: mv /folder1/folder2/folder3/file{,-2013}.txt - Jan Fabry


قم بتشغيل العملية في subshell.

( cd /folder1/folder2/folder3 && mv file.txt file-2013.txt )

لن يتم نشر تغيير دليل العمل إلى shell الأصل.


74
2018-05-17 12:24



+1: يعجبني ذلك ، أكثر قابلية للحمل عبر القذائف من خدعة التوسيد الدعائي (وهي مرتبة ، ولكنها أقل نقالة) - Olivier Dulac
Olivier ، ما الذي يجعلك تعتقد أن توسيع الدعامة ليس محمولًا؟ ما هي القذيفة التي تضعها في اعتبارك والتي لا تدعمها؟ - alexis
لم يتم تحديدalexis Brace expansion بواسطة POSIX ، لذلك فهي غير محمولة "حسب التصميم". ash، dash، ksh88 ناهيك عن قشرة بورني القديمة مثال على قذائف لا تدعمها. - jlliagre
jlliagre أي من الأصداف التي ذكرتها متطابقة تمامًا مع POSIX؟ وهذا يعني أنهم لن يمتلكوا توسيعًا للدعامات حتى لو كان POSIX. كان ksh88 قبل التصديق على POSIX ؛ يجب عليك الترقية إلى ksh93 على الأقل. الشخصان الوحيدان في لينكس يهتمان بالرماد والاندفاع نظرًا لأنهما يستخدمان في بعض التوزيعات الصغيرة المدمجة (busybox، iirc؟) وأقراص الإنقاذ. - Kaz
@ Kaz يهمني قابلية أوامر shell وحقيقة أنها تفاعلية أو لا يهم. بالطبع ، أنت حر بالتأكيد لا تهتم بهذا ، لكن من فضلك أقبل أن يفكر الناس بطريقة أخرى. لا يعني حقيقة استخدامك للباش أو الصدفة التي تدعم توسيع الحواجز دائمًا أن حالة الجميع. - jlliagre


إذا كنت تريد ذكاء ، هنا باش توسيع التاريخ

mv /folder1/folder2/folder3/file.txt !#:1:h/file-2013.txt

لن أستخدم هذا بنفسي لأنني أجد من المستحيل حفظه. أفعل في كل مرة استخدم مكافئ vimولكن يجب أن تبحث عنه في كل مرة تقريبًا.


21
2018-05-17 13:26





يمكنك ضبط متغير. بالطبع هذا له الأثر الجانبي لترك المتغيرات حوله.

D=/folder1/folder2/folder3; mv $D/file.txt $D/file-2013.txt

11
2018-05-17 18:01



وبالطبع ، يمكنك تجنب التأثير الجانبي لترك المتغير (المتغيرات) عن طريق وضع سطر الأوامر بأكمله في قائمة فرعية: (D="/folder1/folder2/folder3"; mv "$D"/file.txt "$D"/file-2013.txt)أو ببساطة عن طريق إضافة unset الأمر في النهاية. (لقد أضفت الاقتباسات كـ "أفضل الممارسات" ؛ إذا كنت تستخدم عادةً علامات اقتباس ، فلن تضطر إلى التوقف وخدش رأسك عندما يأتي اسم مسار يحتوي على أحرف خاصة.) - Scott
Scott إذا كنت ستستخدم قشرة فرعية للتخلص من الآثار الجانبية ، فمن الأسهل القيام بذلك cd من لتعيين متغير. ليس قطعة أرض أسهل ، أعترف. - Isaac Rabinovitch


تعجبني الحلول الأخرى ، لكن هناك طريقة أخرى ، تم تنفيذها كبرنامج نصي مع صفائف bash و pushd و popd:

#!/bin/bash
set -e
# from http://stackoverflow.com/a/246128/178651
script_path="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

# paths relative to the script
relative_paths=( \
path1 \
path2 \
path3 \
path4
)

for relative_path in "${relative_paths[@]}"
do
  pushd "$script_path/$relative_path" > /dev/null 2>&1
  pwd
  mv filename1 filename2
  # could do other stuff in this directory...
  popd > /dev/null 2>&1
done

pushd "$script_path" > /dev/null 2>&1
# could do other stuff in same directory as script...
popd > /dev/null 2>&1

2
2018-05-17 20:30





Slhck يجيب مباشرة على السؤال في أبسط طريقة ممكنة، ولكن فالتر أيضا يحب الإجابة autopop، حتى هنا واحد وهذا على نفس المنوال.

pushd /folder1/folder2/folder3/; mv file.txt file-2013.txt; popd

1
2018-05-21 22:29