முதலையை கடந்து இன்னும் ஒரு ஹைசன்பக்

முதலையை கடந்து இன்னும் ஒரு ஹைசன்பக்

$> set -o pipefail

$> fortune | head -1 > /dev/null && echo "Повезло!" || echo "Вы проиграли"
Повезло!

$> fortune | head -1 > /dev/null && echo "Повезло!" || echo "Вы проиграли"
Вы проиграли

இது fortune நிபந்தனை நிரல் இல்லாமல் exit(rand()).

உன்னால் விளக்க முடியுமா? இங்கே என்ன தவறு?

பாடல்-வரலாற்று விலகல்

நான் முதன்முதலில் இந்த ஹைசன்பக் உடன் கால் நூற்றாண்டுக்கு முன்பு அறிமுகமானேன். பின்னர் FaxNET இல் நுழைவாயிலுக்கு பல பயன்பாடுகளை உருவாக்குவது அவசியம் குழாய்கள் FreeBSD இன் கீழ் "செக்கர்ஸ் விளையாடுகிறது". எதிர்பார்த்தபடி, நான் என்னை ஒரு மேம்பட்ட மற்றும் மிகவும் அனுபவம் வாய்ந்த புரோகிராமர் என்று கருதினேன். எனவே, பிழையைக் கையாள்வதில் சிறப்பு கவனம் செலுத்தி, முடிந்தவரை கவனமாகவும் கவனமாகவும் எல்லாவற்றையும் செய்ய எண்ணினேன்.

செண்ட்மெயில் மற்றும் uucp/uupc இல் உள்ள பிழைகளைக் கையாள்வதில் எனது முந்தைய அனுபவம் "முழுமையான பிழையைக் கையாள்வதில்" எனது விடாமுயற்சியை அதிகரித்தது. அந்தக் கதையின் விவரங்களுக்குள் மூழ்குவதில் எந்தப் பயனும் இல்லை, ஆனால் இந்த ஹைசன்பக் உடன் இரண்டு வாரங்கள் 10-14 மணிநேரம் போராடினேன். எனவே, அது நினைவில் இருந்தது, நேற்று இந்த பழைய அறிமுகம் மீண்டும் பார்க்க நிறுத்தப்பட்டது.

TL;DR பதில்

பயன்பாடு head முடியும் சேனலை மூடு fortune сразу முதல் வரியைப் படித்தவுடன். என்றால் fortune ஒன்றுக்கு மேற்பட்ட வரிகளை வெளியிடுகிறது, பின்னர் தொடர்புடைய அழைப்பு write() ஒரு பிழையை வழங்கும் அல்லது கோரப்பட்டதை விட குறைவான பைட்டுகள் வெளியீடு என்று புகாரளிக்கும். இதையொட்டி, கவனமாக பிழை கையாளுதலுடன் எழுதப்பட்டது fortune இந்த சூழ்நிலையை அதன் வெளியேறும் நிலையில் பிரதிபலிக்க உரிமை உள்ளது. பின்னர் நிறுவல் காரணமாக set -o pipefail வேலை செய்யும் || echo "Вы проиграли".

எனினும், head சரியான நேரத்தில் செய்ய முடியாமல் போகலாம் முன் மூடு fortune தரவுகளை வெளியிடுவதை முடிக்கும். பின்னர் அது வேலை செய்யும் && echo "Повезло!".

இன்று என் ஒன்றில் GNUMakefile அத்தகைய உள்ளது துண்டு:

echo '#define MDBX_BUILD_COMPILER "$(shell set -o pipefail; $(CC) --version | head -1 || echo 'Please use GCC or CLANG compatible compiler')"'

மனிதனாக மொழிபெயர்க்கப்பட்டது

இது இங்கு பொதுவானது குனு மேக் и பாஷ் விருப்பத்தைப் பயன்படுத்தி கம்பைலர் வழியில் --version அவர் யார் என்று அது கேட்கிறது, மேலும் விருப்பம் ஆதரிக்கப்படவில்லை என்றால், ஒரு குட்டை செருகப்படும் "தயவுசெய்து GCC அல்லது CLANG இணக்கமான கம்பைலரைப் பயன்படுத்தவும்".

போன்ற கொதிகலன் எங்கும் காணலாம். இது நீண்ட காலத்திற்கு முன்பு இந்த இடத்தில் தோன்றியது மற்றும் எல்லா இடங்களிலும் சரியாக வேலை செய்தது (Linux, Solaris, OSX, FreeBSD, டபிள்யுஎஸ்எல்லின் முதலியன). ஆனால் நேற்று altlinux மேடையில் எல்ப்ரஸ் 2000 (E2K) நான் கவனித்தேன்:

#define MDBX_BUILD_COMPILER "lcc:1.23.20:Sep--4-2019:e2k-v3-linux Please use GCC or CLANG compatible compiler"

வெளிப்படையாக, எனது பழைய "அறிமுகத்தை" நான் உடனடியாக அடையாளம் காணவில்லை. மேலும், திட்டம் ஏற்கனவே எல்ப்ரஸில் பல முறை சோதிக்கப்பட்டது மற்றும் Alt உட்பட பல்வேறு விநியோகங்களின் கீழ். பல்வேறு கம்பைலர்களுடன், குனு மேக் மற்றும் பாஷின் பதிப்புகள். எனவே, எனது தவறை நான் இங்கு பார்க்க விரும்பவில்லை.

சிக்கலை மீண்டும் உருவாக்க முயற்சிக்கும் போது மற்றும்/அல்லது என்ன நடக்கிறது என்பதைப் புரிந்து கொள்ளும்போது, ​​மேலும் விசித்திரமான விஷயங்கள் நடக்கத் தொடங்கின.
கட்டளை வரி எழுத்துப்பிழை:

echo "#define MDBX_BUILD_COMPILER '$(set -o pipefail; LC_ALL=C cc --version | head -1 || echo "Please use GCC or CLANG compatible compiler")'"

ஒவ்வொரு முறையும் அது கூடுதல் உரையை உருவாக்கும், பின்னர் இல்லை... பெரும்பாலும் விருப்பங்களில் ஒன்று நீண்ட நேரம் ஒட்டிக்கொண்டிருக்கும், ஆனால் நீங்கள் நீண்ட நேரம் குத்தினால், உங்களுக்கு எப்போதும் இரண்டுமே கிடைக்கும்!

நிச்சயமாக, strace எங்கள் எல்லாம்! மேலும் ஒரு ஸ்ட்ரேஸ் டிரேட் டைப் செய்து, ஆனால் என்டரை அழுத்துவதற்கு நேரம் இல்லாததால், எனது பழைய நண்பர் திரு. ஹைசன்பக் மற்றும் டெவலப்பர்களை அடையாளம் கண்டுகொண்டேன். தொகுப்பி நானே 25 வருடங்களுக்கு முன் ஏக்கம்… நான் சோகமாக இருந்து இந்த குறிப்பை எழுத முடிவு செய்தேன்

மூலம், எந்த சுய மரியாதை போன்ற ஹைசன்பக், கீழ் strace இனப்பெருக்கம் செய்ய விரும்பவில்லை.

அதனால் என்ன நடக்கிறது?

  • பயன்பாடு head கேட்கப்பட்ட எண்ணிக்கையிலான வரிகளைப் படித்தவுடன், படிக்கப்படும் சேனலை மூடுவதற்கு உரிமை உள்ளது (அல்லது அதற்கு மாறாக கட்டாயப்படுத்தப்படுகிறது).
  • தரவு உருவாக்கும் நிரல் எழுத்தாளர் (இந்த விஷயத்தில் cc) முடியும் பல வரிகளை அச்சிட மற்றும் இலவசம் பல அழைப்புகள் மூலம் இதைச் செய்யுங்கள் write().
  • என்றால் எழுத்தாளரின் பக்கத்தில் பதிவு முடிவதற்குள் வாசகருக்கு தனது பக்கத்தில் உள்ள சேனலை மூடுவதற்கு நேரம் கிடைக்கும், பின்னர் எழுத்தாளர் பிழையைப் பெறுவார்.
  • எழுத்தாளர் திட்டம் உரிமை உள்ளது இருவரும் சேனல் எழுதும் பிழையைப் புறக்கணித்து, அதை உங்கள் நிறைவுக் குறியீட்டில் பிரதிபலிக்கும்.
  • நிறுவல் காரணமாக set -o pipefail பைப்லைன் நிறைவுக் குறியீடு பூஜ்ஜியமற்றதாக இருக்கும் (தவறானது) முடிவு குறைந்தது ஒரு உறுப்பில் இருந்து பூஜ்ஜியம் அல்லாததாக இருந்தால், அது வேலை செய்யும் || echo "Please use GCC or CLANG compatible compiler".

சிக்னல்களுடன் எழுத்தாளர் நிரல் எவ்வாறு செயல்படுகிறது என்பதைப் பொறுத்து மாறுபாடுகள் இருக்கலாம். எடுத்துக்காட்டாக, நிரல் அசாதாரணமாக முடிவடையும் (பூஜ்ஜியம்/பிழை இல்லாத நிலையின் தானியங்கி உருவாக்கத்துடன்), அல்லது write() கோரியதை விட குறைவான பைட்டுகளை எழுதி அமைத்ததன் முடிவைத் தரும் errno = EPIPE.

யார் குற்றம் சொல்ல வேண்டும்?

விவரிக்கப்பட்ட வழக்கில் எல்லாம் கொஞ்சம். கையாளுவதில் பிழை cc (lcc:1.23.20:Sep—4-2019:e2k-v3-linux) இல்லை தேவைக்கதிகமான. பாரம்பரிய நடத்தைக்காக வடிவமைக்கப்பட்ட கொதிகலனில் திடீர் குறைபாடுகளை இது வெளிப்படுத்தினாலும், பல சந்தர்ப்பங்களில் எச்சரிக்கையுடன் தவறு செய்வது நல்லது.

நான் என்ன செய்ய வேண்டும்?

தவறு:

fortune | head -1 && echo "Повезло, но вы рискуете!" || echo "WTF?"

சரி:

  1. (fortune && echo "Успешно" || echo "Ошибка") | head -1

    இங்கே, உள்ளமைக்கப்பட்ட பைப்லைனுக்கு ("அடைப்புக்குறிக்குள்") சேவை செய்யும் போது, ​​குழாயை முன்கூட்டியே மூடுவது கட்டளை மொழிபெயர்ப்பாளரால் கையாளப்படும். அதன்படி, என்றால் fortune நிலையில் உள்ள மூடிய சேனலுக்கு எழுதுவதில் பிழையைப் புகாரளிக்கும், பின்னர் வெளியீடு || echo "Ошибка" சேனல் ஏற்கனவே மூடப்பட்டிருப்பதால் அது எங்கும் கிடைக்காது.

  2. fortune | cat - | head -1 && echo "Успешно" || echo "Ошибка"

    இதோ உபயோகம் cat பிழையைப் புறக்கணிப்பதால், ஒரு தணிப்பாக செயல்படுகிறது EPIPE திரும்பப் பெறும்போது. இப்போதைக்கு முடிவுக்கு இது போதும் fortune சிறிய (பல கோடுகள்) மற்றும் சேனல் பஃபரில் பொருந்துகிறது (512 பைட்டுகளில் இருந்து ≈64K வரை, பெரும்பாலான OS ≥4K இல்). இல்லையெனில் பிரச்சனை மீண்டும் வரலாம்.

சரியாக செயலாக்குவது எப்படி EPIPE மற்றும் பிற பதிவு பிழைகள்?

சரியான தீர்வு எதுவும் இல்லை, ஆனால் எளிய பரிந்துரைகள் உள்ளன:

  • EPIPE தேவையான செயலாக்கப்பட வேண்டும் (மற்றும் வெளியேறும் நிலையில் பிரதிபலிக்கிறது) ஒருமைப்பாடு தேவைப்படும் தரவை வெளியிடும் போது. எடுத்துக்காட்டாக, காப்பகங்கள் அல்லது காப்புப் பிரதி பயன்பாடுகளின் செயல்பாட்டின் போது.
  • EPIPE புறக்கணிப்பது நல்லது தகவல் மற்றும் துணை செய்திகளைக் காண்பிக்கும் போது. உதாரணமாக, விருப்பங்கள் பற்றிய தகவலைக் காண்பிக்கும் போது --help அல்லது --version.
  • உருவாக்கப்படும் குறியீட்டை முன்பு ஒரு பைப்லைனில் பயன்படுத்தலாம் | head, பின்னர் EPIPE புறக்கணிப்பது நல்லது, இல்லையெனில் செயலாக்க மற்றும் வெளியேறும் நிலையில் பிரதிபலிக்க நல்லது.

அணிகளுக்கு எனது நன்றியைத் தெரிவிக்க இந்த வாய்ப்பைப் பயன்படுத்த விரும்புகிறேன் MCST и altlinux பெரிய உற்பத்தி வேலைக்காக. உங்கள் மன உறுதி அற்புதம்!
தோழிகளே, தொடருங்கள் இலையுதிர் காலத்தில் கூட்டங்கள்!

Спасибо பெரெஸ் எழுத்துப் பிழைகள் மற்றும் பிழைகளைத் திருத்துவதற்கு.
இருந்து KDPV ஜார்ஜி ஏ.

ஆதாரம்: www.habr.com

கருத்தைச் சேர்