ඔව්, අපි බොහෝ දේ දකිමු:
while read line; do
echo $line | cut -c3
done
හෝ ඊට වඩා නරක:
for line in `cat file`; do
foo=`echo $line | awk '{print $2}'`
echo whatever $foo
done
(සිනාසෙන්න එපා, මම ඒවායින් බොහොමයක් දැක ඇත්තෙමි).
සාමාන්යයෙන් ෂෙල් ස්ක්රිප්ටින් ආරම්භකයින්ගෙන්. ඒවා සී හෝ පයිතන් වැනි අත්යවශ්ය භාෂාවලින් ඔබ කරන දේ පිළිබඳ බොළඳ වචනමය පරිවර්තන වේ, නමුත් ඔබ ෂෙල් වෙඩි වලින් දේවල් කරන්නේ එලෙස නොවේ, එම උදාහරණ ඉතා අකාර්යක්ෂම, සම්පූර්ණයෙන්ම විශ්වාස කළ නොහැකි (ආරක්ෂක ගැටළු වලට තුඩු දිය හැකි) සහ ඔබ කවදා හෝ කළමනාකරණය කරන්නේ නම් බොහෝ දෝෂ නිවැරදි කිරීමට, ඔබේ කේතය අවිනිශ්චිත වේ.
සංකල්පමය වශයෙන්
සී හෝ වෙනත් බොහෝ භාෂාවලින්, ගොඩනැඟිලි කොටස් පරිගණක උපදෙස් වලට වඩා එක් මට්ටමකි. ඔබ ඔබේ ප්රොසෙසරයට කුමක් කළ යුතුද, ඊළඟට කුමක් කළ යුතුද යන්න පවසන්න. ඔබ ඔබේ ප්රොසෙසරය අතින් ගෙන එය ක්ෂුද්ර කළමනාකරණය කරයි: ඔබ එම ගොනුව විවෘත කරයි, ඔබ බොහෝ බයිට් කියවන බව කියවයි, ඔබ මෙය කරයි, ඔබ එය කරන්නේ එයයි.
ෂෙල් වෙඩි යනු ඉහළ මට්ටමේ භාෂාවකි. කෙනෙකුට කියන්න පුළුවන් එය භාෂාවක්වත් නැහැ කියලා. ඔවුන් සියලු විධාන රේඛා පරිවර්තකයන්ට පෙරය. කාර්යය සිදු කරනු ලබන්නේ ඔබ ක්රියාත්මක කරන විධානයන් මගිනි. කවචය යනු ඒවා මෙහෙයවීම පමණි.
යුනික්ස් විසින් හඳුන්වා දුන් විශිෂ්ටතම දෙය නම් නල සහ සියලු විධාන පෙරනිමියෙන් හසුරුවන පෙරනිමි stdin / stdout / stderr ප්රවාහයන් ය.
වසර 50 ක් තුළ, විධානවල බලය උපයෝගී කර ගැනීමටත් ඒවා යම් කාර්යයකට සහයෝගය දැක්වීමටත් අපි ඒපීඅයි වලට වඩා හොඳ සොයාගෙන නැත. අදටත් මිනිසුන් ෂෙල් වෙඩි භාවිතා කිරීමට ප්රධාන හේතුව එය විය හැකිය.
ඔබට කැපුම් මෙවලමක් සහ අක්ෂර පරිවර්තන මෙවලමක් ඇත, ඔබට සරලවම කළ හැකිය:
cut -c4-5 < in | tr a b > out
කවචය කරන්නේ ජලනල (ලිපිගොනු විවෘත කිරීම, පයිප්ප සැකසීම, විධාන ඉල්ලා සිටීම) සහ සියල්ල සූදානම් වූ විට එය කවදාවත් නොකර ෂෙල් එකකින් තොරව ගලා යයි. මෙවලම් ඔවුන්ගේ කාර්යය සමගාමීව, කාර්යක්ෂමව තමන්ගේම වේගයෙන් ප්රමාණවත් බෆරයකින් සිදු කරයි, එවිට එකක් අනෙකාට අවහිර නොකෙරේ, එය ලස්සන හා සරල ය.
මෙවලමක් යෙදවීම සඳහා පිරිවැයක් ඇතත් (අපි එය කාර්ය සාධන ලක්ෂ්යය මත සංවර්ධනය කරමු). එම මෙවලම් සී හි උපදෙස් දහස් ගණනක් සමඟ ලිවිය හැකිය. ක්රියාවලියක් නිර්මාණය කළ යුතුය, මෙවලම පැටවිය යුතුය, ආරම්භ කළ යුතුය, පසුව පිරිසිදු කළ යුතුය, ක්රියාවලිය විනාශ වී බලා සිටිය යුතුය.
ආයාචනා කිරීම cut
යනු මුළුතැන්ගෙයි ලාච්චුව විවෘත කිරීම, පිහිය ගැනීම, භාවිතා කිරීම, සේදීම, වියළීම, නැවත ලාච්චුවේ තැබීම වැනි ය. ඔබ එසේ කරන විට:
while read line; do
echo $line | cut -c3
done < file
එය ගොනුවේ සෑම පේළියකටම සමාන ය, read
මුළුතැන්ගෙයි ලාච්චුවෙන් මෙවලම ලබා ගැනීම ( එය ඒ සඳහා නිර්මාණය කර නොමැති නිසා ඉතා අවුල් සහගත ය ), පේළියක් කියවීම, කියවීමේ මෙවලම සෝදා නැවත ලාච්චුවේ තබන්න. ඉන්පසු echo
සහ cut
මෙවලම සඳහා රැස්වීමක් උපලේඛනගත කරන්න , ඒවා ලාච්චුවෙන් ලබා ගන්න, ඒවාට ආරාධනා කරන්න, ඒවා සේදීම, වියළීම, නැවත ලාච්චුවේ තබන්න සහ යනාදිය.
එම මෙවලම් කිහිපයක් ( read
හා echo
) බොහෝ ෂෙල් වෙඩි ඉදි, නමුත් කිසිසේත් සිට මෙහි වෙනසක් බව ද echo
හා cut
තවමත් වෙනම ක්රියාවලි තුළ ක්රියාත්මක කළ යුතුයි.
එය හරියට ළූණු කපනවා වගේ නමුත් ඔබේ පිහිය සෝදා නැවත එක් එක් පෙත්තක් අතර මුළුතැන්ගෙයි ලාච්චුවේ තබන්න.
මෙන්න පැහැදිලිව පෙනෙන ක්රමය නම් ලාච්චුවෙන් ඔබේ cut
මෙවලම ලබා ගැනීම, ඔබේ මුළු ළූණු පෙති කපන්න සහ සම්පූර්ණ කාර්යය අවසන් වූ පසු එය නැවත ලාච්චුවට දමන්න.
IOW, ෂෙල් වෙඩි වලින්, විශේෂයෙන් පෙළ සැකසීමට, ඔබ හැකි තරම් උපයෝගීතා කිහිපයක් ඉල්ලා සිටින අතර ඒවා කාර්යයට සහයෝගය දැක්විය යුතුය, ඊළඟ එක ක්රියාත්මක කිරීමට පෙර සෑම එකක්ම ආරම්භ කිරීමට, ධාවනය කිරීමට, පිරිසිදු කිරීමට බලා සිටින මෙවලම් දහස් ගණනක් අනුපිළිවෙලින් ධාවනය නොකරන්න.
බ ru ස්ගේ කදිම පිළිතුරෙන් වැඩිදුර කියවීම . ෂෙල් වෙඩි වල පහළ මට්ටමේ පෙළ සැකසුම් අභ්යන්තර මෙවලම් (සමහර විට හැර zsh
) සීමිත, අවුල් සහගත සහ සාමාන්ය පෙළ සැකසුම් සඳහා නොගැලපේ.
කාර්ය සාධනය
කලින් කී පරිදි, එක් විධානයක් ධාවනය කිරීම සඳහා පිරිවැයක් දරයි. එම විධානය බිල්ඩින් නොවේ නම් විශාල පිරිවැයක්, නමුත් ඒවා ගොඩනඟා තිබුණත්, පිරිවැය විශාලය.
ෂෙල් වෙඩි එලෙස ධාවනය කිරීමට නිර්මාණය කර නැත, ඒවා ක්රියාකාරී ක්රමලේඛන භාෂාවන් බවට කිසිදු මවාපෑමක් නොමැත. ඔවුන් එසේ නොවේ, ඔවුන් විධාන රේඛා පරිවර්තකයන් පමණි. ඉතින්, මෙම පෙරමුණේ සුළු ප්රශස්තිකරණයක් සිදු කර ඇත.
එසේම, ෂෙල් වෙඩි වෙනම ක්රියාදාමයන්හි විධාන ක්රියාත්මක කරයි. එම ගොඩනැඟිලි කොටස් පොදු මතකයක් හෝ තත්වයක් බෙදා නොගනී. ඔබ C fgets()
හෝ fputs()
C කරන විට, එය stdio හි ශ්රිතයකි. බොහෝ විට මිල අධික පද්ධති ඇමතුම් වළක්වා ගැනීම සඳහා stdio සියළුම stdio කාර්යයන් සඳහා ආදානය සහ ප්රතිදානය සඳහා අභ්යන්තර බෆර තබා ගනී.
අනුරූප ෂෙල් උපයෝගිතා (පවා builtin read
, echo
, printf
) ඒක කරන්න බැහැ. read
එක් පේළියක් කියවීමට අදහස් කෙරේ. එය නව රේඛා අක්ෂරය පසුකර කියවන්නේ නම්, එයින් අදහස් වන්නේ ඔබ ධාවනය කරන ඊළඟ විධානය එය මග හැරෙනු ඇති බවයි. ඒ නිසා read
වරකට ආදානය එක් බයිට් එකක් කියවිය යුතුය (සමහර ක්රියාවට නැංවීම සාමාන්ය ගොනුවක් නම් ඒවා කුට්ටි කියවා ආපසු සොයනු ඇත, නමුත් එය ක්රියාත්මක වන්නේ සාමාන්ය ලිපිගොනු bash
සඳහා පමණක් වන අතර උදාහරණයක් ලෙස කියවන්නේ බයිට් කුට්ටි 128 ක් පමණි තවමත් පෙළ උපයෝගිතා වලට වඩා බොහෝ අඩු වනු ඇත).
ප්රතිදාන පැත්තේ එකම, echo
එහි ප්රතිදානය බෆරයට දැමිය නොහැක, එය කෙළින්ම ප්රතිදානය කළ යුතුය, මන්ද ඔබ ධාවනය කරන ඊළඟ විධානය එම බෆරය බෙදා නොගනී.
නිසැකවම, විධාන අනුපිළිවෙලින් ක්රියාත්මක කිරීම යන්නෙන් අදහස් වන්නේ ඔබ ඔවුන් එනතෙක් බලා සිටිය යුතු බවයි, එය ෂෙල් එකෙන් සහ මෙවලම් සහ පසුපසට පාලනය ලබා දෙන කුඩා උපලේඛන නැටුමකි. එයින් අදහස් වන්නේ (නල මාර්ගයක දිගු කාලීන මෙවලම් භාවිතා කිරීමට වඩා වෙනස්ව) ඔබට එකවර සකසනයන් කිහිපයක් ලබා ගත නොහැකි බවයි.
එම while read
ලූපය හා (යැයි කියනු ලබන) සමාන cut -c3 < file
, මගේ ඉක්මන් පරීක්ෂණයෙහි, මගේ පරීක්ෂණ වල CPU කාල අනුපාතය 40000 ක් පමණ වේ (තත්පරයට එදිරිව දිනකට අඩක්). නමුත් ඔබ ෂෙල් බිල්ඩින් පමණක් භාවිතා කළත්:
while read line; do
echo ${line:2:1}
done
(මෙහි සමඟ bash
), එය තවමත් 1: 600 ක් පමණ වේ (තත්පරයට මිනිත්තු 10 ක්).
විශ්වසනීයත්වය / පැහැදිලි බව
එම කේතය නිවැරදිව ලබා ගැනීම ඉතා අපහසුය. මා දුන් උදාහරණ බොහෝ විට වනයේ දක්නට ලැබේ, නමුත් ඒවාට බොහෝ දෝෂ තිබේ.
read
විවිධ දේ කළ හැකි පහසු මෙවලමකි. එයට පරිශීලකයාගෙන් ආදානය කියවිය හැකිය, විවිධ විචල්යයන්හි ගබඩා කිරීම සඳහා එය වචන වලට බෙදිය හැකිය. read line
නැහැ නැහැ , යෙදවුම් රේඛාවක් කියවන්න, හෝ සමහරවිට එය ඉතා විශේෂ ආකාරයකින් රේඛාවක් කියවනවා. එය ඇත්ත වශයෙන්ම ආදාන වලින් වචන කියවන අතර එම වචන වෙන් කොට $IFS
ඇති අතර බෙදුම්කරුවන්ගෙන් හෝ නව රේඛා අක්ෂරයෙන් ගැලවීමට බැක්ස්ලෑෂ් භාවිතා කළ හැකිය.
වැනි ආදානයක පෙරනිමි අගය සමඟ $IFS
:
foo\/bar \
baz
biz
read line
ගබඩා කරනු ඇත "foo/bar baz"
බවට $line
නැහැ, " foo\/bar \"
ඔබ බලාපොරොත්තු කැමතියි ලෙස.
පේළියක් කියවීමට ඔබට සැබවින්ම අවශ්ය වන්නේ:
IFS= read -r line
එය එතරම් බුද්ධිමත් නොවේ, නමුත් එය එසේ ය, මතක තබා ගන්න ෂෙල් වෙඩි ඒ ආකාරයෙන් භාවිතා කිරීමට අදහස් නොකළ බව.
සඳහා එකම echo
. echo
අනුපිළිවෙල පුළුල් කරයි. අහඹු ගොනුවක අන්තර්ගතය වැනි අත්තනෝමතික අන්තර්ගතයන් සඳහා ඔබට එය භාවිතා කළ නොහැක. printf
ඒ වෙනුවට ඔබට මෙහි අවශ්යයි .
ඇත්ත වශයෙන්ම, සෑම කෙනෙකුම වැටෙන ඔබේ විචල්යය උපුටා දැක්වීම සාමාන්යයෙන් අමතක වේ . එබැවින් එය තවත්:
while IFS= read -r line; do
printf '%s\n' "$line" | cut -c3
done < file
දැන්, තවත් අවවාද කිහිපයක්:
- හැර
zsh
, ආදානයේ NUL අක්ෂර අඩංගු වන්නේ නම් එය ක්රියා නොකරනු ඇති අතර අවම වශයෙන් GNU පෙළ උපයෝගිතා වලට ගැටලුවක් නොමැත.
- අවසාන නව රේඛාවෙන් පසුව දත්ත තිබේ නම්, එය මඟ හරිනු ඇත
- පුඩුවේ ඇතුළත, stdin යළි හරවා යවන බැවින් එහි ඇති විධානයන් stdin වෙතින් කියවන්නේ නැති බව ඔබ අවධානය යොමු කළ යුතුය.
- ලූප තුළ ඇති විධාන සඳහා, ඒවා සාර්ථකද නැද්ද යන්න පිළිබඳව අපි අවධානය යොමු නොකරමු. සාමාන්යයෙන්, දෝෂ (තැටිය පිරී ඇත, කියවීමේ දෝෂ ...) කොන්දේසි දුර්වල ලෙස හසුරුවනු ඇත, සාමාන්යයෙන් නිවැරදි සමානතාවයට වඩා දුර්වල ලෙස .
ඉහත ගැටළු වලින් සමහරක් විසඳීමට අපට අවශ්ය නම්, එය මෙසේ වේ:
while IFS= read -r line <&3; do
{
printf '%s\n' "$line" | cut -c3 || exit
} 3<&-
done 3< file
if [ -n "$line" ]; then
printf '%s' "$line" | cut -c3 || exit
fi
එය අඩු වැඩි වශයෙන් පැහැදිලි වෙමින් පවතී.
තර්ක හරහා විධාන වෙත දත්ත යැවීම හෝ විචල්යයන් තුළ ඒවායේ ප්රතිදානය ලබා ගැනීම සමඟ තවත් ගැටළු ගණනාවක් තිබේ:
- තර්කවල ප්රමාණයට ඇති සීමාව (සමහර පෙළ උපයෝගීතා ක්රියාවට නැංවීමේ සීමාවක් ද ඇත, නමුත් ළඟා වන අයගේ බලපෑම සාමාන්යයෙන් ගැටළු සහගත නොවේ)
- NUL අක්ෂරය (පෙළ උපයෝගිතා සමඟ ද ගැටළුවක්).
- තර්ක
-
(හෝ +
සමහර විට) සමඟ ආරම්භ වන විට විකල්ප ලෙස ගනු ලැබේ
- එම ලූපවල සාමාන්යයෙන් භාවිතා වන විවිධ විධානවල විවිධ විචක්ෂණ
expr
, test
...
- නොගැලපෙන ආකාරයෙන් බහු-බයිට් අක්ෂර හැසිරවිය හැකි විවිධ කවචවල (සීමිත) පෙළ හැසිරවීමේ ක්රියාකරුවන්.
- ...
ආරක්ෂක කරුණු
ඔබ විධාන සඳහා ෂෙල් විචල්යයන් සහ තර්ක සමඟ වැඩ කිරීමට පටන් ගත් විට , ඔබ බිම් බෝම්බ ක්ෂේත්රයකට ඇතුළු වේ.
ඔබේ විචල්යයන් උපුටා දැක්වීමට ඔබට අමතක වුවහොත් , විකල්ප සලකුණුකරුවාගේ අවසානය අමතක කරන්න, බහු-බයිට් අක්ෂර සහිත ස්ථානවල වැඩ කරන්න (මේ දිනවල සම්මතය), ඉක්මනින් හෝ පසුව අවදානම් බවට පත්වන දෝෂ හඳුන්වා දීමට ඔබට විශ්වාසයි.
ඔබට ලූප භාවිතා කිරීමට අවශ්ය වූ විට.
ටී.බී.ඩී.
yes
?