Sed -i (joyida tartibga solish) bilan qanday portativlikka erishishim mumkin?

FreeBSD bilan ishlaydigan umumiy hosting bo'lgan serverim uchun qobiq skriptlarini yozyapman. Bundan tashqari, ularni mahalliy sifatida, Linuxda ishlaydigan shaxsiy kompyuterimda sinab ko'rishni xohlayman. Shuning uchun ularni ko'chma tarzda yozishga harakat qilaman, lekin sed bilan buni amalga oshirish uchun hech qanday usulni ko'rmayapman.

Mening veb-saytimning bir qismi generatsiya qilingan statik HTML-fayllardan foydalanadi va har bir yangilanishdan keyin bu sed LTE to'g'ri DOCTYPE qo'shimchalar:

sed -i '1s/^/<!DOCTYPE HTML> \n/' ${file_name.html}

Linuxda GNU sed bilan ishlaydi, lekin FreeBSD sed zaxira nusxasi uchun kengaytma bo'lishi uchun -y flagidan keyin birinchi dalilni kutadi. Bu shunday ko'rinishda bo'ladi:

sed -i '' '1s/^/<!DOCTYPE HTML> \n/' ${file_name.html}

Biroq, GNU sed o'z navbatida -i-dan keyin darhol amal qilishini kutadi. (Shuningdek, yangi satrlarni qayta ishlash bilan tuzatishlar kiritilgan bo'lsa-da, lekin bu savolga "https://unix.stackexchange.com/questions/42321/how-can-i-instruct-bsd-sent-to-interpret-escape" da javob berilgan. n-and-t/42330 "> bu erda )

Albatta, bu o'zgarishlarni skriptning server nusxasiga qo'shishim mumkin, ammo bu tartibsizlik, ya'ni VCS versiyani ishlatish uchun ishlatiladi. Bunga to'liq ko'chma usulda erishish mumkinmi?

37
qo'shib qo'ydi muallif Arslantabassum, manba
Bergan ikkita parcha qismlari xuddi shunday, sizda typo yo'q ekanligiga ishonchingiz komilmi? Bundan tashqari, -i dan so'ng, zaxira kengaytmasi bilan ta'minlovchi GNU sed-ni bajarishga qodirman.
qo'shib qo'ydi muallif Rudolf L. Jelínek, manba
Duh, buni aniqlash uchun rahmat. Men savolimni aniqladim. Ikkinchi satrda xatolik yuzaga keladi, "1s/^/ \ n/'fayl bo'lishi va uni topa olmasligidan shikoyat qiladi.
qo'shib qo'ydi muallif rbaleksandar, manba

7 javoblar

GNU, -i dan keyin ixtiyoriy kengaytmani qabul qiladi. Kengaytma intervalgacha bo'sh joy bilan bir xil argumentga ega bo'lishi kerak. Ushbu sintaksisi BSD sed-da ishlaydi.

sed -i.bak -e '…' SOMEFILE

UXda -i da bir nechta kirish fayllari mavjud bo'lganida xatti-harakatlar o'zgaradi: ular mustaqil ravishda ishlanadi (masalan, $ har bir faylning oxirgi satriga mos keladi). Bundan tashqari, BusyBox da ishlamaydi.

Agar zaxira fayllaridan foydalanishni xohlamasangiz, sed versiyasining mavjudligini tekshirishingiz mumkin.

case $(sed --help 2>&1) in
  *GNU*) set sed -i;;
  *) set sed -i '';;
esac
"[email protected]" -e '…' "$file"

Yoki muqobil ravishda, joylashuv parametrlarini yopishmaslik uchun, funktsiyani aniqlang.

case $(sed --help 2>&1) in
  *GNU*) sed_i() { sed -i "[email protected]"; };;
  *) sed_i() { sed -i '' "[email protected]"; };;
esac
sed_i -e '…' "$file"

Agar bezovta bo'lishni istamasangiz Perl-dan foydalaning.

perl -i -pe '…' "$file"

Portativ skript yozmoqchi bo'lsangiz, -i dan foydalanmang - bu POSIX-da emas. Qopqoq ostida nima qilsa qo'lni qo'lingiz bilan ishlating - bu faqat bitta kod satridir.

sed -e '…' "$file" >"$file.new"
mv -- "$file.new" "$file"
34
qo'shib qo'ydi
@IvanX Men GNU tizimini sinab ko'rish uchun v buyrug'ining mavjudligini bilishdan ehtiyotman. FreeBSD uni amalga oshirishga qaror qilsa nima bo'ladi?
qo'shib qo'ydi muallif Valters Vingolds, manba
@lapo Muqobil variantni belgilash, tahrirni ko'rish.
qo'shib qo'ydi muallif Valters Vingolds, manba
"$ @" hiyla-nayranglari juda yaxshi, lekin men uni uzoqroq skriptda ishlatmas edim. Afsuski, normal o'zgaruvchilar bu tarzda kengaytirilmaydi (va sh qatorlari mavjud emas), shuning uchun men hech narsa topolmadim.
qo'shib qo'ydi muallif Magnus Johansson, manba
GNU sed -i shuningdek, -s ni ham bildiradi. Va GNU sed kodini tekshirishning eng oson yo'li GNU uchun joriy nooptsiya bo'lgan sed v buyrug'i bilan amalga oshiriladi, ammo hamma joyda muvaffaqiyatsiz bo'ladi.
qo'shib qo'ydi muallif Bill Comer, manba
@Gilles Fair natija, lekin GNU sed uchun odam sahifasi bu maqsad uchun aniqligini tushuntiradi (GNU-ning buzilishi va boshqa hech narsa emasligini aniqlaydi), shuning uchun BSD buni hurmat qiladi. GNU-da, hech qanday operatsiyani boshdan kechirmasdan, boshqa bir sinovni o'ylab topolmayman, ammo u o'z-o'zini ishlatishdan tashqari, BSD sed (yoki aksincha) da xato qilmoqda, ammo bu birinchi navbatda bir dastxat faylini yaratishni talab qiladi. Yuqorida sizning sinovingiz OK, lekin inline uchun noqulay. Sizningcha, taklif qilishingizdan qat'iy nazar, eng ishonchli pul tikish kabi ko'rinadi, lekin men mavjud kodeksni ishlatish uchun sed v ni ishlataman.
qo'shib qo'ydi muallif Ivan X, manba
Yuqoridagi maslahatlardan ilhomlanib, bu erda, agar chindan ham istaganlar uchun bitta (agar u yomon) ko'chma versiyasi bo'lsa, u pastki qismni yaratadi: sed -i $ (sed v /dev/null || echo -n "'' ') -e' ... '" $ fayli " Agar GNU noto'g'ri bo'lmasa, u holda -i </< kodi>, u BSD ustida ishlaydi. GNU sed faqatgina -i ni oladi.
qo'shib qo'ydi muallif Ivan X, manba

Agar siz sed o'ynashni yaxshi qilish uchun aldovni topmasangiz, quyidagilarni qilishingiz mumkin:

  1. Don't use -i :

    sed '1s/^/<!DOCTYPE HTML> \n/' "${file_name.html}" > "${file_name.html}.tmp" &&
      mv "${file_name.html}.tmp" "${file_name.html}"
    
  2. Use Perl

    perl -i -pe 'print "<!DOCTYPE HTML> \n" if $.==1;' "${file_name.html}"
    
10
qo'shib qo'ydi

ed

Mavjud faylga satr qo'shish uchun ed har doim foydalanishingiz mumkin.

$ printf '0a\n<!DOCTYPE HTML>\n.\nw\n' | ed my.html

Batafsil

The bits around the <!DOCTYPE HTML> are commands to ed instructing it to add that line to the file my.html.

sed

Men sed da bu buyruqdan foydalanishga ishonaman:

$ sed -i '1i<!DOCTYPE HTML>\n` testfile.csv
7
qo'shib qo'ydi
@Red - sizni o'zingiz hal qilganingizni eshitganingizdan xursandman. Ha, ilgari men buni ko'rmagan edim, googling uni yoqib yubordi va buni amalga oshirishning eng qulay, eng qulay usuliga o'xshardi.
qo'shib qo'ydi muallif Patrick Szalapski, manba
Oxir-oqibat Perl-ga murojaat qildim, lekin uni ishlatish Unix-ga o'xshagan foydalanuvchilar orasida mashhur bo'lmagan yaxshi alternativ.
qo'shib qo'ydi muallif rbaleksandar, manba

Shuningdek, siz qo'lda nima qilishingiz mumkin: perl -i

{ rm -f file && { echo '<!DOCTYPE HTML>'; cat; } > file;} < file

perl -i kabi, hech qanday zaxira yo'q va bu erda berilgan aksariyat echimlarga o'xshab, u ruxsatnomalarga, fayl egaliklariga ta'sir qilishi mumkin va symlinkni oddiy faylga aylantirishi mumkin.

Bilan:

sed '1i\
<!DOCTYPE HTML>' file 1<> file

sed would overwrite the file over itself, so would not affect ownership and permissions or symlinks. It works with GNU sed because sed will typically have read a buffer full of data from file (4k in my case) before overwriting it with the i command. That wouldn't work if the file was more than 4k except for the fact that sed also buffers its output.

Asosan sed o'qish va yozish uchun 4k bloklar ustida ishlaydi. Agar kiritiladigan satr 4k dan kichik bo'lsa, sed hech qachon o'qilmagan bir blokning ustiga yozilmaydi.

Bunga qaramay, men unga ishonmayman.

7
qo'shib qo'ydi
echo '' bo'lishi yoki "" tirnoqsiz qochib ketishi kerak.
qo'shib qo'ydi muallif Christian Nunciato, manba
@ A.D. Yaxshi fikr. Men interfaol bash/zsh fayllarini buzib tashlashga harakat qilaman, chunki men uni o'zim uchun o'chiraman.
qo'shib qo'ydi muallif Stéphane Chazelas, manba
Bu erda mavjud bo'lgan yoki yo'qligini tekshirmaydigan statik, prognozli nom bilan "temp fayl" ga qayta yo'naltirish uchun keng ochilgan xavfsizlik teshigiga ega bo'lmagan juda bir nechta javoblardan biri. Menimcha, bu qabul qilingan javob bo'lishi kerak. Guruh buyruqlaridan foydalanishning juda yaxshi namoyishidir.
qo'shib qo'ydi muallif Wildcard, manba

FreeBSD sed, which is used on Mac OS X as well, needs the -e option after the -i switch to define & recognise the following (regex) command correctly & unambiguously.

In other words, sed -i -e ... should work with both FreeBSD & GNU sed.

Keyinchalik, FreeBSD sed -i dan so'ng zaxira kengaytmasini qoldirib, ba'zi bir aniq sed parametrini yoki -i ni ta'qib qilishni talab qiladi FreeBSD sed da uning buyruq qatori argumentlarini ajratadi.

(Shunga qaramasdan, sed joyidagi faylni tahrirlash fayl inode o'zgarishiga olib keladi, qarang: " Joylarda "fayllarni tahrirlash ).

(Umumiy ma'lumot sifatida, FreeBSD sed ning so'nggi versiyalari GNU sed bilan muvofiqlikni oshirish uchun -r kalitiga ega).

echo a > testfile.txt
ls -li testfile.txt
#gsed -i -e 's/a/A/' testfile.txt
#bsdsed -i 's/a/A/' testfile.txt  # does not work
bsdsed -i -e 's/a/A/' testfile.txt
ls -li testfile.txt
cat testfile.txt
3
qo'shib qo'ydi
GNU sed-da FreeBSD bilan mos kelish uchun -E (-r-dan tashqari) -ni qo'llab-quvvatlaydi. - E keyingi POSIX versiyasida ko'rsatilishi ehtimoldan holi emas, shuning uchun hammamiz unutmasligimiz kerak.
qo'shib qo'ydi muallif Stéphane Chazelas, manba
Yo'q, bsdsed -i -e/a/A/' - tartibga solish uchun emas, , u asl nusxani "-e" testfile.txt -e ).
qo'shib qo'ydi muallif Stéphane Chazelas, manba

Siz Ex rejimida Vim foydalanishingiz mumkin:

ex -sc '1i|<!DOCTYPE HTML>' -cx file
  1. 1 birinchi qatorni tanlang

  2. i matn va yangi qatorni qo'shing

  3. x saqlash va yopish

1
qo'shib qo'ydi

Mumkin bo'lgan poyga sharoitlaridan qochib, bitta faylga ko'chirish uchun sed -i ni taqlid qilish uchun:

sed 'script' <file
$(cat file)
FILE

Aytgancha, bu ham sed -i katalogida va fayl ruxsatiga qarab, sed -i ga qarab, foydalanuvchini faylni Bu foydalanuvchining tahrirlashga ruxsat yo'q.

Siz kabi zaxira nusxalarini ham yaratishingiz mumkin:

sed 'script' <file
$(tee file.old 
1
qo'shib qo'ydi