“යළි හරවා යැවීම” සහ “නල” අතර වෙනස කුමක්ද?


228

මෙම ප්‍රශ්නය ටිකක් මෝඩකමක් ලෙස පෙනෙන්නට තිබුණද, නැවත හරවා යැවීම සහ පයිප්ප අතර වෙනස මට නොපෙනේ.

නැවත යොමු කිරීම stdout / stdin / stderr නැවත හරවා යැවීමට භාවිතා කරයි, උදා ls > log.txt.

වෙනත් විධානයකට ආදානය ලෙස විධානයක ප්‍රතිදානය ලබා දීමට පයිප්ප භාවිතා කරයි, උදා ls | grep file.txt.

නමුත් එකම දේ සඳහා ක්‍රියාකරුවන් දෙදෙනෙකු සිටින්නේ ඇයි?

ls > grepප්‍රතිදානය හරහා යෑමට පමණක් ලිවිය නොහැක්කේ ඇයි , මෙය නැවත හරවා යැවීමක් පමණක් නොවේද? මට නැති වී ඇත්තේ කුමක්ද?

Answers:


245

ප්‍රතිදානය වෙනත් වැඩසටහනකට හෝ උපයෝගීතාවයකට යැවීමට පයිප් භාවිතා කරයි .

ප්‍රතිදානය ගොනුවකට හෝ ප්‍රවාහයකට යැවීමට යළි-යොමුවීම භාවිතා කරයි .

උදාහරණය: thing1 > thing2එදිරිවthing1 | thing2

thing1 > thing2

  1. ඔබේ කවචය නම් කරන ලද වැඩසටහන ක්‍රියාත්මක කරයි thing1
  2. thing1ප්‍රතිදානය කරන සෑම දෙයක්ම නමින් ගොනුවක තැන්පත් කෙරේ thing2. (සටහන - thing2පවතී නම් එය නැවත ලියනු ලැබේ)

වැඩසටහනේ thing1සිට ප්‍රතිදානය නමින් හැඳින්වෙන වැඩසටහනකට යැවීමට ඔබට අවශ්‍ය නම් thing2, ඔබට පහත සඳහන් දෑ කළ හැකිය:

thing1 > temp_file && thing2 < temp_file

එය

  1. ධාවන වැඩසටහන නම් කර ඇත thing1
  2. ප්‍රතිදානය නම් කරන ලද ගොනුවකට සුරකින්න temp_file
  3. thing2යතුරුපුවරුවේ සිටින පුද්ගලයා temp_fileආදානය ලෙස අන්තර්ගතය ටයිප් කළ බව මවාපාමින් වැඩසටහන ක්‍රියාත්මක කරන්න.

කෙසේ වෙතත්, එය අවුල් සහගත ය, එබැවින් ඔවුන් එය කිරීමට සරල ක්‍රමයක් ලෙස පයිප්ප සෑදුවා. thing1 | thing2ඒ දේම කරනවාthing1 > temp_file && thing2 < temp_file

අදහස් දැක්වීමේදී ප්‍රශ්න සඳහා වැඩි විස්තර සැපයීමට සංස්කරණය කරන්න:

>"වැඩසටහනට පාස් කරන්න" සහ "ගොනුවට ලියන්න" යන දෙකම වීමට උත්සාහ කළහොත් , එය දෙපැත්තෙන්ම ගැටලු ඇති කළ හැකිය.

පළමු උදාහරණය: ඔබ ගොනුවකට ලිවීමට උත්සාහ කරයි. ඔබ නැවත ලිවීමට කැමති එම නම සහිත ගොනුවක් දැනටමත් තිබේ. කෙසේ වෙතත්, ගොනුව ක්රියාත්මක කළ හැකිය. අනුමාන වශයෙන්, එය ආදානය පසුකර මෙම ගොනුව ක්‍රියාත්මක කිරීමට උත්සාහ කරනු ඇත. ප්‍රතිදානය නව ගොනු නාමයකට ලිවීම, ගොනුව නැවත නම් කිරීම වැනි දෙයක් කිරීමට ඔබට සිදුවේ.

දෙවන උදාහරණය: ෆ්ලෝරියන් ඩීෂ් පෙන්වා දුන් පරිදි, පද්ධතියේ වෙනත් නමකින් එකම නමක් ඇති වෙනත් විධානයක් තිබේ නම් (එය ක්‍රියාත්මක කිරීමේ මාවතේ). ඔබගේ වර්තමාන ෆෝල්ඩරයේ එම නම සහිත ගොනුවක් සෑදීමට ඔබ අදහස් කළේ නම්, ඔබ හිර වී සිටිනු ඇත.

තෙවනුව: ඔබ විධානයක් වැරදි ලෙස ටයිප් කළහොත්, විධානය නොපවතින බවට එය අනතුරු අඟවන්නේ නැත. දැන්, ඔබ ටයිප් කළහොත් ls | gerp log.txtඑය ඔබට කියනු bash: gerp: command not foundඇත. >දෙකම අදහස් කරන්නේ නම් , එය ඔබ වෙනුවෙන් නව ගොනුවක් සාදනු ඇත (එවිට කුමක් කළ යුතුදැයි නොදන්නා බවට අනතුරු අඟවන්න log.txt).


ඔබට ස්තුතියි. thing1 > temp_file && thing2 < temp_fileපයිප්ප සමඟ වඩාත් පහසු කිරීමට ඔබ සඳහන් කළා. නමුත් මෙය සිදු කිරීම සඳහා >ක්‍රියාකරු නැවත භාවිතා නොකරන්නේ ඇයි , උදා: thing1 > thing2විධාන සඳහා thing1සහ thing2? අතිරේක ක්‍රියාකරුවෙකු වන්නේ ඇයි |?
ජෝන් ත්රීවුඩ්

1
"ප්‍රතිදානය ගෙන එය ගොනුවකට ලියන්න" යනු "ප්‍රතිදානය ගෙන එය වෙනත් වැඩසටහනකට යොමු කරන්න" යන්නට වඩා වෙනස් ක්‍රියාවකි. මගේ පිළිතුරට තවත් සිතුවිලි සංස්කරණය කරමි ...
ඩේවිඩ් ඔනිල්

1
@ ජෝන් ට්රීප්වුඩ් ඔවුන්ට විවිධ අර්ථයන් ඇත. lessඋදාහරණයක් ලෙස නම් කරන ලද ගොනුවකට යමක් හරවා යැවීමට මට අවශ්‍ය නම් කුමක් කළ යුතුද? thing | lessහා thing > lessඔවුන් විවිධ දේවල් ලෙස, ඉතා හොඳින් වෙනස් වේ. ඔබ යෝජනා කරන දෙයින් අපැහැදිලි බවක් ඇති වේ.
ඩාර්ක්හෝග්

"Thing1> temp_file" යනු "thing1 | tee temp_file" සඳහා හුදෙක් සින්ටැක්ටික් සීනි යැයි පැවසීම නිවැරදිද? ටී ගැන දැනගත් දා සිට මම කිසි විටෙකත් යළි-යොමුවීම් භාවිතා නොකරමි.
ශ්‍රීධර් සර්නොබත්

2
Rid ශ්‍රීධර්-සර්නොබත් නැත, teeවිධානය වෙනස් දෙයක් කරයි. teeතිරය ​​( stdout) සහ ගොනුව යන දෙකටම ප්‍රතිදානය ලියයි . යළි-යොමුවීම කරන්නේ ගොනුව පමණි .
ඩේවිඩ් ඔනිල්

24

එහි අර්ථය foo > barරඳා පවතින්නේ නම් කරන ලද විධානයක් barනැවත හරවා යැවීම භාවිතා කිරීම වඩා දුෂ්කර හා දෝෂ සහිත විය හැකි ද යන්න මත ය: මට ගොනුවකට හරවා යැවීමට අවශ්‍ය සෑම අවස්ථාවකම මගේ ගමනාන්ත ගොනුව වැනි විධානයක් තිබේදැයි පරීක්ෂා කිරීමට මට සිදු විය.


මෙය ගැටළුවක් වනු ඇත්තේ ඔබ barඔබේ $PATHenv විචල්‍යයේ කොටසක් වන නාමාවලියකට ලියන්නේ නම් පමණි . ඔබ / බින් වැනි දෙයක් තුළ සිටී නම්, එවිට ගැටළුවක් විය හැකිය. නමුත් එසේ වුවද, barක්‍රියාත්මක කළ හැකි අවසර කට්ටලයක් තිබිය යුතුය, එවිට ෂෙල් පරීක්‍ෂා කරන්නේ ක්‍රියාත්මක කළ හැකි දෙයක් සොයා ගැනීම සඳහා barපමණක් නොව එය ක්‍රියාත්මක කළ හැකිය. දැනට පවතින ගොනුව නැවත ලිවීම ගැන සැලකිලිමත් වන්නේ නම්, නැවත nocloberහරවා යැවීමේදී පවතින ලිපිගොනු නැවත ලිවීම ෂෙල් විකල්පය විසින් වළක්වා ගත යුතුය.
සර්ජි කොලොඩියාෂ්නි

21

යුනික්ස් සහ ලිනක්ස් පද්ධති පරිපාලන අත්පොතෙන්:

යළි හරවා යැවීම

කවචය <,>, සහ >> යන සංකේත විධාන වල ආදානය හෝ ප්‍රතිදානය ගොනුවකට හෝ ඉන් පිටතට හරවා යැවීමට උපදෙස් ලෙස අර්ථ දක්වයි .

පයිප්ප

එක් STDOUT සම්බන්ධ කිරීමට අණ වන STDIN කිරීමට තවත් භාවිතය | සංකේතය, පොදුවේ නල ලෙස හැඳින්වේ.

එබැවින් මගේ අර්ථ නිරූපණය මෙයයි: එය අණ කිරීමට අණ නම්, පයිප්පයක් භාවිතා කරන්න. ඔබ ගොනුවකට හෝ ඉන් ප්‍රතිදානය කරන්නේ නම් යළි-යොමුවීම භාවිතා කරන්න.


13

ක්‍රියාකරුවන් දෙදෙනා අතර වැදගත් වෙනසක් ඇත:

  1. ls > log.txt -> මෙම විධානය මඟින් ප්‍රතිදානය log.txt ගොනුවට යවයි.

  2. ls | grep file.txt-> මෙම විධානය මඟින් ls හි ප්‍රතිදානය grep විධානයට පයිප්ප ( |) භාවිතයෙන් යවන අතර grep විධානය පෙර විධානය මඟින් සපයන ලද ආදානයේ file.txt සෙවීම.

පළමු අවස්ථාව භාවිතා කරමින් ඔබට එකම කාර්යය කිරීමට සිදු වූයේ නම්, එය එසේ වනු ඇත:

ls > log.txt; grep 'file.txt' log.txt

එබැවින් |ප්‍රතිදානය වෙනත් විධානයකට යැවීමට පයිප්පයක් (සමඟ ) >භාවිතා කරන අතර ප්‍රතිදානය යම් ගොනුවකට හරවා යැවීම සඳහා යළි- යොමුවීම (සමඟ ) භාවිතා කරයි.


4

මේ දෙක අතර විශාල සින්ටැක්ටික් වෙනසක් ඇත:

  1. යළි-යොමුවීමක් යනු වැඩසටහනකට තර්කයකි
  2. පයිප්පයක් විධාන දෙකක් වෙන් කරයි

මේ වගේ යළි-යොමුවීම් ගැන ඔබට සිතිය හැකිය : cat [<infile] [>outfile]. මෙයින් ගම්‍ය වන්නේ ඇණවුම වැදගත් නොවන බවයි: cat <infile >outfileසමාන වේ cat >outfile <infile. ඔබ පවා අනෙකුත් තර්ක සමඟ යළි-යොමුකරයි දක්වා මිශ්ර කළ හැකි: cat >outfile <infile -bසහ cat <infile -b >outfileදෙකම හොඳින් හොඳින්. ඔබට ආදාන හෝ ප්‍රතිදානයන් එකකට වඩා එකට ගැට ගැසිය හැකිය (යෙදවුම් අනුපිළිවෙලින් කියවනු ලබන අතර සෑම ප්‍රතිදානයක්ම එක් එක් ප්‍රතිදාන ගොනුවට ලියනු ලැබේ) : cat >outfile1 >outfile2 <infile1 <infile2. යළි-යොමුවීමක ඉලක්කය හෝ ප්‍රභවය ගොනු නාමයක් හෝ ප්‍රවාහයක නම විය හැකිය (& 1 වැනි, අවම වශයෙන් බෑෂ් වලින්).

නමුත් පයිප්ප එක් විධානයක් වෙනත් විධානයකින් මුළුමනින්ම වෙන් කරයි, ඔබට ඒවා තර්ක සමඟ මිශ්‍ර කළ නොහැක:

[command1] | [command2]

පයිප්ප විධාන 1 සිට සම්මත නිමැවුමට ලියා ඇති සියල්ල රැගෙන විධාන 2 හි සම්මත ආදානය වෙත යවයි.

ඔබට නල මාර්ග සහ නැවත හරවා යැවීමද ඒකාබද්ධ කළ හැකිය. උදාහරණයක් වශයෙන්:

cat <infile >outfile | cat <infile2 >outfile2

පළමුවැන්නා catඉන්ෆයිල් වෙතින් පේළි කියවන අතර, එකවර එක් එක් පේළිය පිටතට ලිවීමට හා දෙවැන්න වෙත යවනු ඇත cat.

දෙවන cat, සම්මත ආදාන පළමු නල (infile අන්තර්ගතය) සිට කියවන, එවිට outfile2 එක් එක් රේඛාව ලියන, infile2 සිට කියවනවා. මෙය ක්‍රියාත්මක කිරීමෙන් පසු, පිටපත infile හි පිටපතක් වන අතර outfile2 හි infile2 පසුව infile2 අඩංගු වේ.

අවසාන වශයෙන්, ඔබ ඇත්ත වශයෙන්ම "මෙහි නූල්" යළි හරවා යැවීම (බැෂ් පවුලට පමණි) සහ පසුපෙළ භාවිතා කරමින් ඔබේ උදාහරණයට සැබවින්ම සමාන දෙයක් කරයි:

grep blah <<<`ls`

ප්‍රති result ලයම ලබා දෙනු ඇත

ls | grep blah

නමුත් මම සිතන්නේ යළි-යොමුවීමේ අනුවාදය පළමුවෙන්ම ls හි සියලු ප්‍රතිදානය බෆරයකට (මතකයේ) කියවනු ඇති අතර, පසුව එම බෆරය වරකට එක පේළියක් ග්‍රහණය කර ගැනීම සඳහා පෝෂණය කරනු ඇත, නමුත් නල අනුවාදය සෑම පේළියක්ම ඉස්මතු වන විට ls වෙතින් ගනු ඇත, එම රේඛාව grep වෙත යොමු කරන්න.


1
Nitpick: ඔබ එක් fd එකක් තවත් දෙසට හරවා යැවුවහොත් ඇණවුම නැවත හරවා යැවීමේදී වැදගත් වේ: echo yes 1>&2 2>/tmp/blah; wc -l /tmp/blah; echo yes 2>/tmp/blah 1>&2; wc -l /tmp/blahතවද, ගොනුවකට හරවා යැවීම භාවිතා කරන්නේ අවසාන යළි- යොමුවීම පමණි. echo yes >/tmp/blah >/tmp/blah2වෙත පමණක් ලියනු ඇත /tmp/blah2.
මුරු

2
යළි-යොමුවීම ඇත්ත වශයෙන්ම වැඩසටහනට තර්කයක් නොවේ. වැඩසටහන එහි ප්‍රතිදානය යන්නේ කොතැනට දැයි නොදැන හෝ සැලකිලිමත් නොවේ (හෝ ආදානය පැමිණෙන්නේ). වැඩසටහන ක්‍රියාත්මක කිරීමට පෙර දේවල් පිළියෙළ කරන්නේ කෙසේදැයි බාෂ්ට පැවසීමේ ක්‍රමය එයයි.
ඇලෝයිස් මහඩාල්

4

සටහන: පිළිතුර මෙම වෙබ් අඩවියේ සහ යුනික්ස්.ස්ටැක්එක්ස්චේන්ජ්.කොම් හි සම වයසේ මිතුරන් විසින් පර්යේෂණ හා කියවීම් පිළිබඳව රැස්කර ගෙන ඇති මෙම යාන්ත්‍රණයන් පිළිබඳ මගේම අවබෝධය පිළිබිඹු කරයි, කාලයත් සමඟ යාවත්කාලීන වේ. ප්‍රශ්න ඇසීමට පසුබට නොවන්න. විධාන සමඟ ෂෙල් තුළ සිස්කල් ක්‍රියා කරන්නේ කෙසේදැයි බැලීමට උත්සාහ කරන ලෙස මම ඔබට යෝජනා කරමි strace. කරුණාකර අභ්‍යන්තර හෝ සිස්කල් යන සංකල්පයෙන් බිය නොවන්න - ෂෙල් දේවල් කරන්නේ කෙසේද යන්න තේරුම් ගැනීම සඳහා ඔබට ඒවා දැන ගැනීමට හෝ භාවිතා කිරීමට අවශ්‍ය නැත, නමුත් ඒවා අනිවාර්යයෙන්ම තේරුම් ගැනීමට උපකාරී වේ.

ටීඑල්; ඩී.ආර්

  • |පයිප්ප තැටියේ ඇතුළත් කිරීමක් සමඟ සම්බන්ධ නොවේ, එබැවින් තැටි ගොනු පද්ධතියේ ඉනෝඩ අංකයක් නොමැත (නමුත් කර්නල්-අවකාශයේ පයිප්ෆ් අතථ්‍ය ගොනු පද්ධතියේ ඉනෝඩ ඇත ), නමුත් යළි-යොමුවීම් බොහෝ විට ලිපිගොනු ඇතුළත් වන අතර ඒවාට තැටි ඇතුළත් කිරීම් ඇති අතර එම නිසා අනුරූප වේ ඉනෝඩය.
  • පයිප්පවලට lseek()නොහැකි බැවින් විධාන වලට සමහර දත්ත කියවා නැවත පෙරළා දැමිය නොහැක, නමුත් ඔබ එය හරවා යවන විට >හෝ <සාමාන්‍යයෙන් එය ගොනුවක් විය lseek()හැකි බැවින් විධාන වලට කැමති පරිදි සැරිසැරීමට හැකිය.
  • යළි-යොමුවීම් යනු ගොනු විස්තර කරන්නන් මත සිදුකරන උපාමාරු ය, ඒවා බොහෝ විය හැකිය; පයිප්ප සතුව ඇත්තේ ගොනු විස්තර දෙකක් පමණි - එකක් වම් විධානය සඳහා සහ එකක් දකුණු විධානය සඳහා ය
  • සම්මත ධාරා සහ පයිප්ප නැවත හරවා යැවීම දෙකම ආරක්ෂිත වේ.
  • පයිප්ප සෑම විටම පාහේ දෙබලක සම්බන්ධ වන අතර එම නිසා ක්‍රියාවලි යුගල සම්බන්ධ වේ; යළි-යොමුවීම් - සෑම විටම නොවේ, මෙම අවස්ථා දෙකෙහිම ප්‍රති ing ලයක් ලෙස ගොනු විස්තර කරන්නන් උප ක්‍රියාවලි මගින් උරුම වේ.
  • පයිප්ප සැමවිටම ගොනු විස්තර කරන්නන් (යුගලයක්) සම්බන්ධ කරයි, යළි-යොමුවීම් - එක්කෝ මාර්ග නාමයක් හෝ ගොනු විස්තරයක් භාවිතා කරන්න.
  • පයිප්ප අන්තර් ක්‍රියාදාම සන්නිවේදන ක්‍රමයක් වන අතර, යළි-යොමුවීම් යනු විවෘත ලිපිගොනු හෝ ගොනු වැනි වස්තූන් හසුරුවීම පමණි
  • dup2()සත්‍ය දත්ත ප්‍රවාහයක් සිදුවන ලිපිගොනු විස්තර කරුවන්ගේ පිටපත් සැපයීම සඳහා දෙදෙනාම කබායට යටින් සිස්කල් භාවිතා කරති .
  • යළි-යොමුවීම් "ගෝලීයව" execබිල්ට් විධාන සමඟ යෙදිය හැකිය ( මෙය සහ මෙය බලන්න ), එබැවින් ඔබ කරන්නේ නම් exec > output.txtසෑම විධානයක්ම output.txtඑතැන් සිට ලියනු ඇත. |පයිප්ප යොදවන්නේ වත්මන් විධානය සඳහා පමණි (එයින් අදහස් කරන්නේ සරල විධානයක් හෝ උප-ෂෙල් වැනි seq 5 | (head -n1; head -n2)හෝ සංයුක්ත විධාන සඳහා ය.
  • ලිපිගොනු නැවත හරවා යැවීම සිදු කළ විට, වැනි දේ echo "TEST" > fileසහ echo "TEST" >> fileදෙකම open()එම ගොනුවේ syscall භාවිතා කරයි ( මෙයද බලන්න ) සහ එය ලබා දීමට ගොනු විස්තරයක් ලබා ගන්න dup2(). පයිප්ප |පමණක් භාවිතා pipe()සහ dup2()syscall.
  • යළි-යොමුවීම් වලට ගොනු සහ නාමාවලි අවසර ඇතුළත් වේ; නිර්නාමික පයිප්පවල සාමාන්‍යයෙන් අවසරයන් ඇතුළත් නොවේ (එනම් ඔබට පයිප්පයක් සෑදිය හැකිද නැද්ද යන්න), නමුත් නම් කරන ලද පයිප්ප (සාදන ලද mkfifo) සාමාන්‍ය ගොනු අවසරයන් සහ කියවීම්-ලිවීම්-ක්‍රියාත්මක කිරීමේ බිටු ඇතුළත් වේ.
  • විධාන ක්‍රියාත්මක වන තාක් දුරට, පයිප්ප සහ යළි හරවා යැවීම ගොනු විස්තර කරන්නන්ට වඩා වැඩි නොවේ - ලිපිගොනු වැනි වස්තූන්, ඒවා අන්ධ ලෙස ලිවීමට හෝ අභ්‍යන්තරව හැසිරවීමට (ඒවා අනපේක්ෂිත හැසිරීම් ඇති කළ හැකිය; aptනිදසුනක් ලෙස, stdout වෙත ලිවීමට පවා නැඹුරු වේ. නැවත හරවා යැවීමක් ඇති බව එය දන්නේ නම්).

හැදින්වීම

මෙම යාන්ත්‍රණ දෙක එකිනෙකට වෙනස් වන්නේ කෙසේද යන්න තේරුම් ගැනීම සඳහා, ඒවායේ අත්‍යවශ්‍ය ගුණාංග, දෙක පිටුපස ඇති ඉතිහාසය සහ සී ක්‍රමලේඛන භාෂාවෙන් ඒවායේ මූලයන් තේරුම් ගැනීම අවශ්‍ය වේ. ඇත්ත වශයෙන්ම, ගොනු විස්තර කරන්නන් යනු කුමක්ද dup2()සහ pipe()පද්ධති ඇමතුම් ක්‍රියා කරන්නේ කෙසේද සහ කෙසේද යන්න දැන ගැනීම අත්‍යවශ්‍ය වේ lseek(). ෂෙල් යනු මෙම යාන්ත්‍රණයන් පරිශීලකයාට වියුක්ත කිරීමේ ක්‍රමයක් ලෙස අදහස් කරන නමුත් වියුක්තයට වඩා ගැඹුරට හෑරීම ෂෙල්ගේ හැසිරීමේ සැබෑ ස්වභාවය තේරුම් ගැනීමට උපකාරී වේ.

යළි-යොමුවීම් සහ පයිප්පවල මූලාරම්භය

ඩෙනිස් Ritche ලිපිය අනුව අනාවැකි ඉතිහාසය තුල මතභේද , පයිප්ප වලින් සම්භවය 1964 අභ්යන්තර සටහනක් විසින් මැල්කම් ඩග්ලස් ලහිරුගේ , ඔවුන් කටයුතු කරමින් සිටින අවස්ථාවක Multics පද්දතිය මෙහෙයුම් පද්ධතිය . උපුටා ගැනීම:

මගේ ශක්තිමත්ම කරුණු කෙටියෙන් කිවහොත්:

  1. උද්‍යාන හෝස් වැනි වැඩසටහන් සම්බන්ධ කිරීමට අපට ක්‍රම කිහිපයක් තිබිය යුතුය - වෙනත් ආකාරයකින් දත්ත සම්බාහනය කිරීමට අවශ්‍ය වූ විට තවත් කොටසකට ඉස්කුරුප්පු කරන්න. IO හි මාර්ගය ද මෙයයි.

පෙනෙන දෙය නම්, එකල වැඩසටහන් තැටියට ලිවීමේ හැකියාව තිබූ නමුත් ප්‍රතිදානය විශාල නම් එය අකාර්යක්ෂම වීමයි. යුනික්ස් පයිප්ලයින් වීඩියෝවෙන් බ්‍රයන් කර්නිගන් ගේ පැහැදිලි කිරීම උපුටා දැක්වීමට :

පළමුවෙන්ම, ඔබට එක් විශාල දැවැන්ත වැඩසටහනක් ලිවීමට අවශ්‍ය නැත - ඔබ සතුව දැනටමත් පවතින කුඩා වැඩසටහන් තිබේ, ඒවා දැනටමත් කාර්යයේ කොටස් කළ හැකිය ... තවත් දෙයක් නම්, ඔබ ප්‍රොසෙස් කරන දත්ත ප්‍රමාණය නොගැලපේ නම් ඔබ එය ගොනුවක ගබඩා කර ඇත ... මන්ද මතක තබා ගන්න, මේ දේවල් පිළිබඳ තැටි තිබූ දිනවල, අපි වාසනාවන්ත නම්, මෙගාබයිට් එකක් හෝ දත්ත දෙකක් තිබුනි ... එබැවින් නල මාර්ගයට කිසි විටෙකත් සම්පූර්ණ ප්‍රතිදානය ක්ෂණිකව කිරීමට සිදු නොවීය. .

මේ අනුව සංකල්පීය වෙනස පැහැදිලිව පෙනේ: පයිප්ප යනු වැඩසටහන් එකිනෙකා සමඟ කතා කිරීමේ යාන්ත්‍රණයකි. යළි-යොමුවීම් - මූලික මට්ටමින් ගොනු කිරීමට ලිවීමේ ක්‍රමයකි. අවස්ථා දෙකේදීම, ෂෙල් විසින් මේ කාරණා දෙක පහසු කරයි, නමුත් කබායට යටින්, සිදුවෙමින් පවතින බොහෝ දේ ඇත.

ගැඹුරට යාම: සිස්කල් සහ කවචයේ අභ්‍යන්තර කටයුතු

අපි ආරම්භ කරන්නේ ගොනු විස්තර කරන්නා යන සංකල්පයෙන් . ගොනු විස්තර කරන්නන් මූලික වශයෙන් විස්තර කරන්නේ විවෘත ගොනුවක් (එය තැටියේ හෝ මතකයේ හෝ නිර්නාමික ගොනුවක් වේවා), එය පූර්ණ සංඛ්‍යාවක් මගින් නිරූපණය කෙරේ. සම්මත දත්ත ප්‍රවාහයන් දෙක (stdin, stdout, stderr) පිළිවෙලින් ගොනු විස්තර කරන්නන් 0,1 සහ 2 වේ. ඔවුන් කොහේ ඉඳන්ද ? හොඳයි, ෂෙල් විධාන වලදී ගොනු විස්තර කරන්නන් ඔවුන්ගේ මව් - ෂෙල් වෙතින් උරුම වේ. සෑම ක්‍රියාවලියක් සඳහාම එය පොදුවේ සත්‍යයකි - ළමා ක්‍රියාවලිය දෙමව්පියන්ගේ ලිපිගොනු විස්තර කරන්නන්ට උරුම වේ. ඩීමන් සඳහා, උරුම වී ඇති සියලුම ගොනු විස්තර වසා දැමීම සහ / හෝ වෙනත් ස්ථාන වෙත හරවා යැවීම සාමාන්‍ය දෙයකි.

නැවත හරවා යැවීම වෙත. ඇත්තටම එය කුමක්ද? එය විධානය සඳහා ගොනු විස්තර සකස් කිරීමට ෂෙල්ට පවසන යාන්ත්‍රණයකි (මක්නිසාද යත් විධානය ක්‍රියාත්මක වීමට පෙර නැවත හරවා යැවීම ෂෙල් මඟින් සිදු කරන බැවිනි), සහ පරිශීලකයා යෝජනා කළ ස්ථානයට ඒවා යොමු කරන්න. මෙම සම්මත අර්ථ දැක්වීම ප්රතිදානය හරවා යැවීමේ වනුයේ

[n]>word

[n]ගොනුව descriptor අංකය නැත. ඔබ කරන echo "Something" > /dev/nullවිට අංක 1 එහි ගම්‍ය වේ, සහ echo 2> /dev/null.

dup2()පද්ධති ඇමතුම හරහා ගොනු විස්තරය අනුපිටපත් කිරීමෙන් මෙය සිදු කෙරේ . අපි ගනිමු df > /dev/null. කවචය ක්‍රියාත්මක වන ළමා ක්‍රියාවලියක් නිර්මාණය කරනු ඇත df, නමුත් ඊට පෙර එය ගොනු විස්තර කරන්නා /dev/null# 3 ලෙස විවෘත වන අතර dup2(3,1)එය නිකුත් කරනු ඇත, එමඟින් ගොනු විස්තර 3 හි පිටපතක් සාදනු ඇති අතර එහි පිටපත 1 වනු ඇත. ඔබට ලිපිගොනු දෙකක් ඇති ආකාරය file1.txtසහ file2.txt, සහ ඔබ කරන විට ඔබට cp file1.txt file2.txtඑකම ලිපිගොනු දෙකක් ඇත, නමුත් ඔබට ඒවා ස්වාධීනව හැසිරවිය හැකිද? ඒකත් මෙතනමයි. ධාවනය වීමට පෙර, පසුව bashඑය යථා dup(1,10)තත්වයට පත් කිරීම සඳහා පිටපත් ගොනු විස්තරයක් # 1 stdout(සහ එම පිටපත fd # 10 වනු ඇත) කිරීමට බොහෝ විට ඔබට දැක ගත හැකිය . වැදගත් වන්නේ ඔබ විසින් සාදන ලද විධාන සලකා බලන විටය(ඒවා කවචයේම කොටසක් වන අතර කිසිදු ගොනුවක් /binහෝ වෙනත් තැනක නොමැත) හෝ අන්තර්ක්‍රියාකාරී නොවන කවචයේ සරල විධානයන් , කවචය ළමා ක්‍රියාවලියක් නිර්මාණය නොකරයි.

ඉන් පසුව අපි වැනි දේවල් ඇති [n]>&[m]හා [n]&<[m]. මෙය ගොනු විස්තර කරුවන් අනුපිටපත් කිරීමකි, එය dup2()දැන් පවතින යාන්ත්‍රණයම ෂෙල් සින්ටැක්ස් තුළ ඇති අතර එය පරිශීලකයාට පහසුවෙන් ලබා ගත හැකිය.

නැවත හරවා යැවීම පිළිබඳව සැලකිල්ලට ගත යුතු වැදගත් කරුණක් නම් ඒවායේ ඇණවුම සවි කර නොමැති නමුත් පරිශීලකයාට අවශ්‍ය දේ ෂෙල් විසින් අර්ථ නිරූපණය කරන්නේ කෙසේද යන්න වැදගත් වේ. පහත සඳහන් දෑ සසඳා බලන්න:

# Make copy of where fd 2 points , then redirect fd 2
$ ls -l /proc/self/fd/  3>&2  2> /dev/null
total 0
lrwx------ 1 user user 64 Sep 13 00:08 0 -> /dev/pts/0
lrwx------ 1 user user 64 Sep 13 00:08 1 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:08 2 -> /dev/null
lrwx------ 1 runner user 64 Sep 13 00:08 3 -> /dev/pts/0
lr-x------ 1 user user 64 Sep 13 00:08 4 -> /proc/29/fd

# redirect fd #2 first, then clone it
$ ls -l /proc/self/fd/    2> /dev/null 3>&2
total 0
lrwx------ 1 user user 64 Sep 13 00:08 0 -> /dev/pts/0
lrwx------ 1 user user 64 Sep 13 00:08 1 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:08 2 -> /dev/null
l-wx------ 1 user user 64 Sep 13 00:08 3 -> /dev/null
lr-x------ 1 user user 64 Sep 13 00:08 4 -> /proc/31/fd

ෂෙල් ස්ක්‍රිප්ටින්හි මේවා ප්‍රායෝගිකව භාවිතා කිරීම බහුකාර්ය විය හැකිය:

සහ තවත් බොහෝ දේ.

සමග, ජලනල කාර්මික ශිල්පය pipe()සහdup2()

ඉතින් පයිප්ප නිර්මාණය කරන්නේ කෙසේද? හරහා pipe()syscall , ආදාන ලෙස නම් (ලැයිස්තුව හෙවත්) රැසක් ගෙන ඇත pipefdවර්ගයේ භාණ්ඩ දෙකක් int(පූර්ණ සංඛ්යාවක්). එම නිඛිල දෙක ගොනු විස්තර කරන්නන් වේ. මෙම pipefd[0]නල යන කියවා අවසන් වනු ඇති අතර, pipefd[1]ලිවීම් අවසන් වනු ඇත. ඒ නිසා දී df | grep 'foo', grepපිටපතක් ලබා ඇත pipefd[0]හා dfපිටපතක් ලබා ඇත pipefd[1]. නමුත් කෙසේද? ඇත්ත වශයෙන්ම, dup2()සිස්කල්ගේ මැජික් සමඟ . සඳහා dfඅපගේ නිදසුනේ, එහෙනම් අපි කිව්වොත් pipefd[1]ෂෙල්, ළමා කළ නිසා ඇත කරන්නේ, # 4 ඇත dup2(4,1)(මගේ මතක cpඋදාහරණයක්?), පසුව කරන්නේ execve()ඇත්තටම ක්රියාත්මක කිරීමට df. ස්වාභාවිකවම,dfගොනු විස්තර කරන්නා # 1 උරුම කර ගනු ඇත, නමුත් එය තවදුරටත් පර්යන්තයට යොමු නොවන බව නොදැන සිටියි, නමුත් ඇත්ත වශයෙන්ම fd # 4, එය ඇත්ත වශයෙන්ම පයිප්පයේ ලිවීමේ අවසානය වේ. ස්වාභාවිකවම, grep 'foo'විවිධ ගොනු විස්තර කිරීම් හැරුණු විට එකම දේ සිදුවනු ඇත .

දැන්, සිත්ගන්නාසුලු ප්‍රශ්නය: fd # 1 පමණක් නොව fd # 2 යළි හරවා යවන පයිප්ප සෑදිය හැකිද? ඔව්, ඇත්ත වශයෙන්ම එයයි |&. POSIX ප්‍රමිතියට df 2>&1 | grep 'foo'එම අරමුණු සඳහා සින්ටැක්ස් සඳහා සහය දැක්වීමට ෂෙල් විධාන භාෂාව අවශ්‍ය වන නමුත් bashඑය |&එසේම වේ.

සැලකිල්ලට ගත යුතු වැදගත්ම දෙය නම් පයිප්ප සෑම විටම ගොනු විස්තර කරන්නන් සමඟ කටයුතු කිරීමයි. තැටියේ ගොනු නාමයක් ඇති නළයක් තිබේ FIFOහෝ නම් කර ඇති අතර ඔබ එය ගොනුවක් ලෙස භාවිතා කරමු, නමුත් පයිප්පයක් මෙන් හැසිරේ. නමුත් |පයිප්ප වර්ග යනු නිර්නාමික පයිප්ප ලෙස හැඳින්වේ - ඒවාට ගොනු නාමයක් නොමැත, මන්ද ඒවා සැබවින්ම එකට සම්බන්ධ වී ඇති වස්තු දෙකක් පමණි. අප ලිපිගොනු සමඟ ගනුදෙනු නොකිරීමද වැදගත් ඇඟවීමක් කරයි: පයිප්පවලට lseek()නොහැකි ය. ලිපිගොනු, මතකයේ හෝ තැටියේ ස්ථිතික වේ - වැඩසටහන් වලට lseek()සිස්කාල් භාවිතා කර බයිට් 120 වෙත පනින්න, පසුව බයිට් 10 වෙත ආපසු යන්න, ඉන්පසු අවසානය දක්වා ඉදිරියට යන්න. පයිප්ප ස්ථිතික නොවේ - ඒවා අනුක්‍රමික වන අතර එම නිසා ඔබට ඒවායින් ලැබෙන දත්ත නැවත පෙරළා දැමිය නොහැකlseek(). සමහර වැඩසටහන් ගොනුවෙන් හෝ පයිප්පයෙන් කියවන්නේ නම් මෙය දැනුවත් කරයි, එබැවින් කාර්යක්ෂම කාර්ය සාධනය සඳහා අවශ්‍ය වෙනස්කම් කළ හැකිය; වෙනත් වචන වලින් කිවහොත්, progමා එසේ කරන්නේ නම් cat file.txt | progහෝ හඳුනාගත හැකිය prog < input.txt. ඒ සඳහා සැබෑ වැඩ උදාහරණය වලිගයයි .

පයිප්පවල ඇති අනෙක් ඉතා සිත්ගන්නාසුලු දේපල දෙක නම්, ඔවුන් සතුව බෆරයක් ඇති අතර එය ලිනක්ස් හි බයිට් 4096 ක් වන අතර ඇත්ත වශයෙන්ම ඒවා ලිනක්ස් ප්‍රභව කේතයේ අර්ථ දක්වා ඇති පරිදි ගොනු පද්ධතියක් ඇත ! ඒවා හුදෙක් දත්ත සම්ප්‍රේෂණය කිරීමේ වස්තුවක් නොවේ, ඒවා දත්ත ව්‍යුහයකි! ඇත්ත වසයෙන් ම, පවතී ජලනල හා FIFOs දෙකම කළමනාකරණය කරනු ලබන pipefs ගොනු පද්ධතිය, නිසා, පයිප්ප සඳහා inode ඇති අදාළ ගොනු පද්ධතිය මත අංකය:

# Stdout of ls is wired to pipe
$ ls -l /proc/self/fd/  | cat  
lrwx------ 1 user user 64 Sep 13 00:02 0 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:02 1 -> pipe:[15655630]
lrwx------ 1 user user 64 Sep 13 00:02 2 -> /dev/pts/0
lr-x------ 1 user user 64 Sep 13 00:02 3 -> /proc/22/fd
# stdin of ls is wired to pipe
$ true | ls -l /proc/self/fd/0
lr-x------ 1 user user 64 Sep 13 03:58 /proc/self/fd/0 -> 'pipe:[54741]'

ලිනක්ස් පයිප්ප හරවා යැවීම මෙන් ඒක දිශානුගත වේ. සමහර යුනික්ස් වැනි ක්‍රියාත්මක කිරීම් වලදී - ද්වි-දිශානුගත පයිප්ප ඇත. ෂෙල් ස්ක්‍රිප්ටින් මැජික් සමඟ වුවද, ඔබට ලිනක්ස් මත ද්වි-දිශානුගත පයිප්ප සෑදිය හැකිය .

මෙයද බලන්න:


3

අනෙක් පිළිතුරු වලට එකතු කිරීම සඳහා, සියුම් අර්ථකථන වෙනසක් ද ඇත - උදා: නැවත හරවා යැවීමට වඩා පයිප්ප පහසුවෙන් වසා දමයි:

seq 5 | (head -n1; head -n1)                # just 1
seq 5 > tmp5; (head -n1; head -n1) < tmp5   # 1 and 2
seq 5 | (read LINE; echo $LINE; head -n1)   # 1 and 2

පළමු උදාහරණයේ දී, පළමු ඇමතුම headඅවසන් වූ විට, එය නළය වසා seqදමා අවසන් වේ, එබැවින් දෙවැන්න සඳහා ආදානයක් නොමැත head.

දෙවන උදාහරණයේ දී, හිස පළමු පේළිය පරිභෝජනය කරයි, නමුත් එය තමන්ගේම stdin නළය වසා දැමූ විට , ඊළඟ ඇමතුම භාවිතා කිරීම සඳහා ගොනුව විවෘතව පවතී.

තෙවන උදාහරණයෙන් පෙනී යන්නේ අප readනළය වැසීම වළක්වා ගැනීමට භාවිතා කරන්නේ නම් එය තවමත් උප ක්‍රියාවලිය තුළ පවතින බවයි.

එබැවින් "ප්‍රවාහය" යනු අපි (stdin etc) හරහා දත්ත ඉවත් කරන දෙය වන අතර එය අවස්ථා දෙකේදීම එක හා සමාන වේ, නමුත් නළය ක්‍රියාවලි දෙකකින් ධාරාවන් සම්බන්ධ කරයි, එහිදී යළි හරවා යැවීම ක්‍රියාවලියක් සහ ගොනුවක් අතර ධාරාවක් සම්බන්ධ කරයි, එබැවින් ඔබ සමානකම් හා වෙනස්කම් යන දෙකෙහිම මූලාශ්‍රය දැකිය හැකිය.

PS ඔබ මා වැනි උදාහරණ ගැන කුතුහලයෙන් හා / හෝ පුදුමයට පත් වී trapඇත්නම්, ක්‍රියාවලි නිරාකරණය වන ආකාරය බැලීමට ඔබට තවදුරටත් හාරා ගත හැකිය , උදා:

(trap 'echo seq EXITed >&2' EXIT; seq 5) | (trap 'echo all done' EXIT; (trap 'echo first head exited' EXIT; head -n1)
echo '.'
(trap 'echo second head exited' EXIT; head -n1))

සමහර විට 1මුද්‍රණය කිරීමට පෙර පළමු ක්‍රියාවලිය වසා දමයි , සමහර විට පසුව.

exec <&-පයිප්පයේ හැසිරීම ආසන්න වශයෙන් දැක්වීම සඳහා යළි හරවා යැවීමේ සිට ධාරාව වැසීමට භාවිතා කිරීම සිත්ගන්නාසුළු විය (දෝෂයක් තිබුණද):

seq 5 > tmp5
(trap 'echo all done' EXIT
(trap 'echo first head exited' EXIT; head -n1)
echo '.'
exec <&-
(trap 'echo second head exited' EXIT; head -n1)) < tmp5`

"හිසට පළමු ඇමතුම අවසන් වූ විට, එය නළය වසා දමයි" මෙය ඇත්ත වශයෙන්ම හේතු දෙකක් නිසා සාවද්‍ය ය. එකක්, (head -n1; head -n1) විධාන දෙකකින් සමන්විත වන අතර, ඒ සෑම එකක්ම පයිප්පයේ කියවීමේ අවසානය විස්තර කරන්නා 0 ලෙස උරුම කර ගනී, එබැවින් උපසෙල් සහ සෑම විධානයකටම එම ගොනු විස්තරය විවෘතව පවතී. දෙවන හේතුව, ඔබට එය strace -f bash -c 'seq 5 | සමඟ දැකිය හැකිය (head -n1; head -n1) '. එබැවින් පළමු හිස වසා
දමන්නේ

තෙවන උදාහරණය ද සාවද්‍ය ය, මන්ද readපරිභෝජනය කරන්නේ පළමු පේළිය පමණි (එය එක් බයිට් එකක් 1සහ නව රේඛාවක් ). seqමුළු බයිට් 10 කින් (අංක 5 සහ නව රේඛා 5) යවන ලදි. පයිප්ප බෆරයේ බයිට් 8 ක් ඉතිරිව ඇති අතර, දෙවනුව headක්‍රියා කරන්නේ එබැවිනි - පයිප්ප බෆරයේ තවමත් දත්ත තිබේ. Btw, හිස පිටවන්නේ බයිට් 0 ක් කියවා ඇත්නම් පමණි, තරමක් දුරටhead /dev/null
සර්ජි කොලොඩියාස්නි

පැහැදිලි කිරීම සඳහා ස්තූතියි. බව මම මම නිවැරදිව තේරුම් seq 5 | (head -n1; head -n1)විවෘත රාජ්ය නමුත් දෙවන ඇමතුම සඳහා දත්ත සමඟ එය තවමත් පවතින නිසා පළමු ඇමතුම, නල අතහරී head? ඉතින් නළය සහ යළි-යොමුවීම අතර හැසිරීමේ වෙනස වන්නේ හිස සියලු දත්ත පයිප්පයෙන් ඉවතට ඇද ගන්නා නමුත් ගොනු හසුරුවලින් පේළි 2 ක් පමණක්ද?
ජූලියන් ද භාල්

එය නිවැරදිය. එය straceපළමු විවරණයේ දී මා දුන් විධානයෙන් දැකිය හැකි දෙයකි . යළි හරවා යැවීමත් සමඟ, tmp ගොනුව තැටියේ ඇති අතර එය සෙවිය හැකි ය (ඔවුන් lseek()syscall භාවිතා කරන නිසා - විධාන වලට පළමු බයිට් සිට අන්තිම දක්වා ගොනුව වටා පනින්න පුළුවන්. නමුත් පයිප්ප අනුක්‍රමික වන අතර ඒවා සෙවිය නොහැක. එබැවින් හිසට එය කළ හැකි එකම ක්‍රමය කාර්යය නම් සියල්ල මුලින්ම කියවීම හෝ ගොනුව විශාල නම් - එයින් සමහරක් mmap()ඇමතුම හරහා RAM වෙත සිතියම් ගත tail
කරන්න.මම

පයිප්පයේ කියවීමේ අවසානය (ගොනු විස්තර කරන්නා) මුලින් ලබා දී ඇති බව මතක තබා ගැනීම ද වැදගත් වන අතර (...), උපසෙල් එක තුළ ඇති සෑම විධානයකටම තමන්ගේම ස්ටයිඩින් පිටපතක් ලබා දෙනු ඇත (...). එබැවින් ඒවා තාක්‍ෂණිකව එකම වස්තුවකින් කියවනු ලැබේ. පළමුවෙන්ම head සිතන්නේ එය කියවන්නේ තමන්ගේම දෑවලින් බවයි. දෙවැන්න headසිතන්නේ එයට එයටම ආවේණික වූ බවයි. නමුත් යථාර්ථයේ දී ඔවුන්ගේ fd # 1 (stdin) යනු එකම fd පිටපතක් වන අතර එය පයිප්පයේ අවසානය කියවනු ලැබේ. එසේම, මම පිළිතුරක් පළ කර ඇත, එබැවින් සමහර විට එය කරුණු පැහැදිලි කිරීමට උපකාරී වනු ඇත.
සර්ජි කොලොඩියාෂ්නි

2

මම අද සී හි මේ සම්බන්ධයෙන් ගැටලුවකට මුහුණ දුන්නා. අත්‍යාවශ්‍යයෙන්ම පයිප් වෙත යවන විට පවා යළි-යොමුවීම් සඳහා විවිධ අර්ථකථන ඇත stdin. ඇත්ත වශයෙන්ම මම සිතන්නේ වෙනස්කම් අනුව, පයිප්ප හැර වෙනත් තැනකට යා යුතුය stdin, එවිට stdinඑය ඇමතීමට ඉඩ දෙයි stdpipe(අත්තනෝමතික අවකලනය කිරීමට) විවිධ ආකාරවලින් හැසිරවිය හැකිය.

මෙය සලකා බලන්න. තවත් එක් වැඩසටහනක් නිෂ්පාදනය ගිනි අඟුරුවල විට fstatශුන්ය ලෙස නැවත පෙනේ st_sizeතිබියදීත් ls -lha /proc/{PID}/fdගොනු ඇති බව පෙන්නුම් කරයි. ගොනුව නැවත යොමුකිරීම විට මෙම නඩුව (අවම වශයෙන් Debian මත නොවේ wheezy, stretchසහ jessieවැනිලා සහ උබුන්ටු 14.04, 16.04වැනිලා.

ඔබ cat /proc/{PID}/fd/0යළි හරවා යැවීමක් කළහොත් ඔබට කැමති වාර ගණනක් කියවීමට නැවත නැවත කළ හැකිය. ඔබ මෙය පයිප්පයකින් කළහොත් දෙවන වරටත් ඔබ එම කාර්යය අඛණ්ඩව ක්‍රියාත්මක කරන බව ඔබට පෙනෙනු ඇත, ඔබට එකම ප්‍රතිදානය නොලැබේ.

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.