البحث والاستبدال في الملف والكتابة فوق الملف لا يعمل ، فإنه يفرغ الملف

سئل على ٢ مارس ٢٠١١  ·  تمت مشاهدة 720.2k مرة  ·  مصدر

BBales picture
في ٢ مارس ٢٠١١

أرغب في إجراء بحث واستبدال في ملف HTML من خلال سطر الأوامر.

يبدو أمري مثل هذا:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html > index.html

عندما أقوم بتشغيل هذا والنظر إلى الملف بعد ذلك ، فهو فارغ. لقد حذف محتويات ملفي.

عندما أقوم بتشغيل هذا بعد استعادة الملف مرة أخرى:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

stdout هي محتويات الملف ، وتم تنفيذ البحث والاستبدال.

لماذا يحدث هذا؟

الإجابات

codaddict picture
في ٢ مارس ٢٠١١
932

عندما يرى shell > index.html في سطر الأوامر ، يفتح الملف index.html للكتابة ، ويمسح جميع محتوياته السابقة.

لإصلاح ذلك ، تحتاج إلى تمرير الخيار -i إلى sed لإجراء التغييرات المضمنة وإنشاء نسخة احتياطية من الملف الأصلي قبل إجراء التغييرات في مكانها:

sed -i.bak s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

بدون .bak ، سيفشل الأمر في بعض الأنظمة الأساسية ، مثل Mac OSX.

Norman Gray picture
في ٢ مارس ٢٠١١
211

النمط البديل والمفيد هو:

sed -e 'script script' index.html > index.html.tmp && mv index.html.tmp index.html

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

الكثير من سيارات السيدان لديها الخيار -i ، لكن ليس جميعها ؛ إن posix sed هو الذي لا يفعل ذلك. إذا كنت تهدف إلى قابلية النقل ، فمن الأفضل تجنب ذلك.

Rich Apodaca picture
في ٩ أغسطس ٢٠١٣
95
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' index.html

يقوم هذا باستبدال عام في المكان في ملف index.html. يمنع اقتباس السلسلة حدوث مشاكل مع المسافات البيضاء في الاستعلام والاستبدال.

Kevin picture
في ٢ مارس ٢٠١١
57

استخدم خيار sed's -i ، على سبيل المثال

sed -i bak -e s/STRING_TO_REPLACE/REPLACE_WITH/g index.html
Stenemo picture
في ٢٠ يونيو ٢٠١٣
18

لتغيير ملفات متعددة (وحفظ نسخة احتياطية من كل منها بتنسيق * .bak):

perl -p -i -e "s/\|/x/g" *  

سوف يأخذ جميع الملفات في الدليل ويستبدل | بـ x وهذا يسمى "Perl pie" (سهل مثل فطيرة)

uloBasEI picture
في ٢ مارس ٢٠١١
14

يجب أن تحاول استخدام الخيار -i للتحرير الموضعي.

xealits picture
في ١٧ يوليو ٢٠١٣
7

تحذير: هذه طريقة خطيرة! إنه يسيء استخدام مخازن الإدخال / الإخراج في لينكس ومع خيارات محددة للتخزين المؤقت فإنه يدير العمل على الملفات الصغيرة. إنه فضول مثير للاهتمام. لكن لا تستخدمه في وضع حقيقي!

بجانب الخيار -i لـ sed يمكنك استخدام الأداة المساعدة tee .

من man :

نقطة الإنطلاق - قراءة من الإدخال القياسي والكتابة إلى الإخراج والملفات القياسية

لذا ، فإن الحل سيكون:

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee | tee index.html

- هنا يتم تكرار tee للتأكد من أن خط الأنابيب مخزّن. ثم يتم حظر جميع الأوامر الموجودة في خط الأنابيب حتى تحصل على بعض المدخلات للعمل عليها. يبدأ كل أمر في خط الأنابيب عندما تكتب أوامر المنبع مخزنًا مؤقتًا واحدًا من البايت (يتم تحديد الحجم في مكان ما ) لإدخال الأمر. لذا فإن الأمر الأخير tee index.html ، الذي يفتح الملف للكتابة وبالتالي يفرغه ، يعمل بعد انتهاء خط الأنابيب الرئيسي ويكون الإخراج في المخزن المؤقت داخل خط الأنابيب.

على الأرجح لن يعمل ما يلي:

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee index.html

- سيتم تشغيل كلا الأمرين لخط الأنابيب في نفس الوقت دون أي حظر. (بدون حظر خط الأنابيب يجب أن يمر البايت سطراً بسطر بدلاً من المخزن المؤقت بواسطة المخزن المؤقت. كما هو الحال عند تشغيل cat | sed s/bar/GGG/ . بدون حظر ، يكون الأمر أكثر تفاعلية وعادة ما يتم تشغيل خطوط الأنابيب المكونة من أمرين فقط بدون تخزين مؤقت أو حظر. خطوط الأنابيب الطويلة يتم تخزينها مؤقتًا.) سيفتح tee index.html الملف للكتابة وسيتم إفراغه. ومع ذلك ، إذا قمت بتشغيل التخزين المؤقت دائمًا ، فسيعمل الإصدار الثاني أيضًا.

Kaey picture
في ٩ أكتوبر ٢٠١٥
6
sed -i.bak "s#https.*\.com#$pub_url#g" MyHTMLFile.html

إذا كان لديك ارتباط لإضافته ، جرب هذا. ابحث عن عنوان URL على النحو الوارد أعلاه (يبدأ بـ https وينتهي بـ.com هنا) واستبدله بسلسلة عنوان URL. لقد استخدمت متغير $pub_url هنا. s هنا يعني البحث و g يعني الاستبدال العالمي.

إنها تعمل !

Andrzej Pronobis picture
في ٣٠ يوليو ٢٠١٥
4

المشكلة مع الأمر

sed 'code' file > file

هو أن file يتم اقتطاعه بواسطة الغلاف قبل أن يقوم sed بمعالجته. نتيجة لذلك ، تحصل على ملف فارغ.

طريقة sed للقيام بذلك هي استخدام -i للتعديل في المكان ، كما اقترحت الإجابات الأخرى. ومع ذلك ، هذا ليس دائمًا ما تريده. سينشئ -i ملفًا مؤقتًا يستخدم بعد ذلك لاستبدال الملف الأصلي. هذا يمثل مشكلة إذا كان ملفك الأصلي رابطًا (سيتم استبدال الرابط بملف عادي). إذا كنت بحاجة إلى الاحتفاظ بالروابط ، فيمكنك استخدام متغير مؤقت لتخزين إخراج sed قبل إعادة كتابته إلى الملف ، على النحو التالي:

tmp=$(sed 'code' file); echo -n "$tmp" > file

والأفضل من ذلك ، استخدم printf بدلاً من echo لأن echo من المحتمل أن يعالج \\ كـ \ في بعض القذائف (مثل شرطة):

tmp=$(sed 'code' file); printf "%s" "$tmp" > file
glenn jackman picture
في ٢٨ يونيو ٢٠١١
3

والإجابة ed :

printf "%s\n" '1,$s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' w q | ed index.html

لتكرار ما أجاب المدمن ، يتعامل الغلاف مع إعادة التوجيه أولاً ، ويمسح ملف "input.html" ، ثم يستدعي shell الأمر "sed" ويمرره إلى ملف فارغ الآن.