විචල්ය ආෙද්ශක සහ විධාන ආෙද්ශක පමණ, උද්ධෘත පාඨ සෑම විටම භාවිතා කරන්න: "$foo"
,"$(foo)"
ඔබ $foo
නොකැඩූ ලෙස භාවිතා කරන්නේ නම් , ඔබේ ස්ක්රිප්ට් $(foo)
සුදු අවකාශය අඩංගු ආදාන හෝ පරාමිතීන් (හෝ විධාන ප්රතිදානය සමඟ ) යටපත් කරයි \[*?
.
එහිදී ඔබට කියවීම නැවැත්විය හැකිය. හොඳයි, හරි, මෙන්න තවත් කිහිපයක්:
read
- බිල්ඩින් සමඟ පේළි අනුව ආදාන රේඛාව කියවීම සඳහා read
,while IFS= read -r line; do …
ප්ලේන් read
ට්රීට්ස් බැක්ස්ලෑෂ් සහ වයිට්ස්පේස් විශේෂයෙන් භාවිතා කරන්න.
xargs
- වළකින්නxargs
. ඔබ භාවිතා කළ යුතු නම් xargs
, එය සාදන්න xargs -0
. ඒ වෙනුවට find … | xargs
, කැමති වන්නfind … -exec …
.
xargs
හිස් අවකාශය සහ චරිත \"'
විශේෂයෙන් සලකයි .
මේ පිළිතුර Bourne / POSIX ආකාරයේ ෂෙල් වෙඩි අදාළ ( sh
, ash
, dash
, bash
, ksh
, mksh
, yash
....) Zsh භාවිතා කරන්නන් එය මඟ හැරිය යුතු අතර ද්විත්ව උපුටා දැක්වීම අවශ්ය වන්නේ කවදාද? වෙනුවට. ඔබට සම්පූර්ණ අවශ්යතාවය අවශ්ය නම්, සම්මත හෝ ඔබේ කවචයේ අත්පොත කියවන්න.
පහත දැක්වෙන පැහැදිලි කිරීම්වල දළ වශයෙන් ස්වල්පයක් අඩංගු බව සලකන්න (බොහෝ තත්වයන් තුළ සත්ය වන නමුත් අවට සන්දර්භය හෝ වින්යාසය මගින් බලපෑම් කළ හැකි ප්රකාශ).
මට ලිවීමට අවශ්ය ඇයි "$foo"
? උපුටා දැක්වීම් නොමැතිව කුමක් සිදුවේද?
$foo
“විචල්යයේ අගය ගන්න” යන්නෙන් අදහස් නොවේ foo
. එයින් අදහස් කරන්නේ වඩා සංකීර්ණ දෙයක්:
- පළමුව, විචල්යයේ අගය ගන්න.
- ක්ෂේත්ර බෙදීම: එම අගය හිස් අවකාශයකින් වෙන් කළ ක්ෂේත්ර ලැයිස්තුවක් ලෙස සලකන්න, එහි ප්රති ing ලයක් ලෙස ලැයිස්තුව සාදන්න. උදාහරණයක් ලෙස, විචල්ය අඩංගු නම්
foo * bar
එවිට මෙම පියවර ප්රතිඵලයක් 3-අංගයක් ලැයිස්තුව foo
, *
, bar
.
- ගොනු නාම උත්පාදනය: සෑම ක්ෂේත්රයක්ම ගෝලීය ලෙස සලකන්න, එනම් ආදේශක රටාවක් ලෙස සලකන්න, සහ මෙම රටාවට ගැලපෙන ගොනු නාම ලැයිස්තුවෙන් එය ප්රතිස්ථාපනය කරන්න. රටාව කිසිදු ලිපිගොනුවකට නොගැලපේ නම්, එය නවීකරණය නොකෙරේ. අපගේ උදාහරණයේ දී, මෙහි ප්රති results
foo
ලය වනුයේ වත්මන් නාමාවලියෙහි ඇති ගොනු ලැයිස්තුවෙන් පසුව, අවසානයේ අඩංගු වන ලැයිස්තුවයි bar
. වත්මන් බහාළුම හිස් නම්, එහි ප්රතිඵලය වන්නේ foo
, *
, bar
.
ප්රති result ලය නූල් ලැයිස්තුවක් බව සලකන්න. ෂෙල් සින්ටැක්ස් හි සන්දර්භ දෙකක් ඇත: ලැයිස්තු සන්දර්භය සහ නූල් සන්දර්භය. ක්ෂේත්ර බෙදීම් සහ ගොනු නාම උත්පාදනය සිදුවන්නේ ලැයිස්තු සන්දර්භය තුළ පමණි, නමුත් එය බොහෝ විට සිදු වේ. ද්විත්ව උපුටා දැක්වීම් නූල් සන්දර්භයක් සීමා කරයි: මුළු ද්විත්ව-උපුටා ගත් නූල බෙදීමට නොයන තනි නූලකි. (ව්යතිරේකය: "$@"
ස්ථානීය පරාමිති ලැයිස්තුවට ව්යාප්ත කිරීම සඳහා, උදා: ස්ථානීය පරාමිතීන් තුනක් "$@"
තිබේ "$1" "$2" "$3"
නම් එය සමාන වේ . බලන්න $ * සහ $ between අතර වෙනස කුමක්ද? )
විධාන ආදේශ කිරීම සමඟ $(foo)
හෝ සමඟ සිදු `foo`
වේ. පැත්තක සටහනක, භාවිතා නොකරන්න `foo`
: එහි උපුටා දැක්වීමේ නීති අමුතු හා අතේ ගෙන යා නොහැකි ඒවා වන අතර, නවීන ෂෙල් වෙඩි සඳහා සහය දක්වන්නේ $(foo)
බුද්ධිමය උපුටා දැක්වීමේ නීති හැරෙන්නට නියත වශයෙන්ම සමාන වේ.
අංක ගණිත ආදේශනයේ ප්රතිදානය ද එකම ප්රසාරණයකට භාජනය වේ, නමුත් එය සාමාන්යයෙන් සැලකිලිමත් වන්නේ එය පුළුල් කළ නොහැකි අක්ෂර පමණක් අඩංගු වන හෙයිනි ( IFS
ඉලක්කම් හෝ නැතැයි උපකල්පනය කරයි -
).
බලන්න අවශ්ය ද්විත්ව උපුටා දක්වමින් විට? ඔබට උපුටා දැක්වීම් අතහැර දැමිය හැකි අවස්ථා පිළිබඳ වැඩි විස්තර සඳහා.
මේ සියලු රිග්මරෝලය සිදුවීමට ඔබ අදහස් නොකරන්නේ නම්, සෑම විටම විචල්ය සහ විධාන ආදේශක වටා ද්විත්ව මිල ගණන් භාවිතා කිරීමට මතක තබා ගන්න. සැලකිලිමත් වන්න: උපුටා දැක්වීම් පිටවීම දෝෂ වලට පමණක් නොව ආරක්ෂක වළලු වලට ද හේතු විය හැක .
ගොනු නාම ලැයිස්තුවක් සකසන්නේ කෙසේද?
myfiles="file1 file2"
ලිපිගොනු වෙන් කිරීම සඳහා අවකාශයන් සමඟ ඔබ ලියන්නේ නම් , මෙය හිස් අවකාශයන් සහිත ගොනු නම් සමඟ ක්රියා කළ නොහැක. යුනික්ස් ලිපිගොනු නාමවල /
(සෑම විටම නාමාවලි බෙදුම්කරුවෙකු වන) සහ ශුන්ය බයිට් (ඔබට බොහෝ ෂෙල් වෙඩි ඇති ෂෙල් ස්ක්රිප්ට් වල භාවිතා කළ නොහැකි) හැර වෙනත් අක්ෂර අඩංගු විය හැකිය .
එකම ගැටලුව myfiles=*.txt; … process $myfiles
. ඔබ මෙය කරන විට, විචල්යයේ myfiles
අක්ෂර 5 කින් යුත් නූලක් අඩංගු වන අතර *.txt
, ඔබ ලියන $myfiles
විට ආදේශක කාඩ්පත පුළුල් වේ. ඔබ ඔබේ ස්ක්රිප්ට් එක වෙනස් කරන තුරු මෙම උදාහරණය සැබවින්ම ක්රියාත්මක myfiles="$someprefix*.txt"; … process $myfiles
වේ. someprefix
සකසා ඇත්නම් final report
, මෙය ක්රියා නොකරනු ඇත.
ඕනෑම ආකාරයක ලැයිස්තුවක් සැකසීමට (ගොනු නාම වැනි), එය අරාවකට දමන්න. මේ සඳහා mksh, ksh93, yash හෝ bash (හෝ zsh, මේ සියලු උපුටා දැක්වීමේ ගැටළු නොමැති) අවශ්ය වේ; සරල POSIX කවචයකට (අළු හෝ ඉරක් වැනි) අරාව විචල්යයන් නොමැත.
myfiles=("$someprefix"*.txt)
process "${myfiles[@]}"
Ksh88 හි වෙනස් පැවරුම් සින්ටැක්ස් සහිත අරාව විචල්යයන් ඇත set -A myfiles "someprefix"*.txt
( ඔබට ksh88 / bash portability අවශ්ය නම් විවිධ ksh පරිසරය යටතේ පැවරුම් විචල්යය බලන්න ). බෝර්න් / පොසික්ස් විලාසිතාවේ ෂෙල් වෙඩි සඳහා තනි අරා එකක් ඇත, "$@"
ඔබ පිහිටුවා ඇති ස්ථානීය පරාමිතීන් සමූහයක් set
සහ ශ්රිතයකට දේශීය වේ:
set -- "$someprefix"*.txt
process -- "$@"
ආරම්භ වන ගොනු නාම ගැන කුමක් කිව -
හැකිද?
ආශ්රිත සටහනක, ගොනු නාමයන් -
(ඩෑෂ් / us ණ) සමඟ ආරම්භ කළ හැකි බව මතක තබා ගන්න, බොහෝ විධානයන් අර්ථ නිරූපණය කරන්නේ විකල්පයක් ලෙසය. සමහර විධානයන් (වැනි sh
, set
හෝ sort
) ආරම්භ වන විකල්ප පිළිගනී +
. ඔබට විචල්ය කොටසකින් ආරම්භ වන ගොනු නාමයක් තිබේ --
නම්, ඉහත ස්නිපටයේ මෙන් එය පෙර සම්මත කිරීමට වග බලා ගන්න . මෙය විකල්පයේ අවසානයට ළඟා වී ඇති බවට විධානයට ඇඟවුම් කරයි, එබැවින් ඉන් පසුව ඕනෑම දෙයක් ගොනු නාමයක් වන අතර එය ආරම්භ වුවද -
හෝ +
වේ.
විකල්පයක් ලෙස, ඔබේ ගොනු නාම හැර වෙනත් අක්ෂරයකින් ආරම්භ වන බවට ඔබට සහතික විය හැකිය -
. නිරපේක්ෂ ගොනු නාම වලින් ආරම්භ /
වන අතර ඔබට ./
සාපේක්ෂ නම් ආරම්භයේදී එකතු කළ හැකිය . පහත දැක්වෙන ස්නිපටය මඟින් විචල්යයේ අන්තර්ගතය f
ආරම්භ කිරීම -
හෝ නොකිරීම සහතික කරන එකම ගොනුව වෙත යොමු කිරීමේ “ආරක්ෂිත” ක්රමයක් බවට පත් කරයි +
.
case "$f" in -* | +*) "f=./$f";; esac
මෙම මාතෘකාව පිළිබඳ අවසාන සටහනක, සමහර විධානයන් -
සම්මත ආදානය හෝ සම්මත ප්රතිදානය ලෙස අර්ථකථනය කරන බවට පරිස්සම් වන්න --
. ඔබට නම් කරන ලද සත්ය ගොනුවක් වෙත යොමු වීමට අවශ්ය නම් -
, හෝ ඔබ එවැනි වැඩසටහනක් අමතන්නේ නම් සහ එය stdin වෙතින් කියවීමට හෝ stdout වෙත ලිවීමට ඔබට අවශ්ය නැතිනම්, -
ඉහත පරිදි නැවත ලිවීමට වග බලා ගන්න . බලන්න "du -sh *" සහ "du -sh ./*" අතර වෙනස කුමක්ද? වැඩිදුර සාකච්ඡා සඳහා.
විචල්යයක විධානයක් ගබඩා කරන්නේ කෙසේද?
“විධානය” යන්නට කරුණු තුනක් අදහස් කළ හැකිය: විධාන නාමයක් (ක්රියාත්මක කළ හැකි නමක්, සම්පූර්ණ මාර්ගයක් සහිතව හෝ රහිතව, හෝ ශ්රිතයක නම, බිල්ඩින් හෝ අන්වර්ථය), තර්ක සහිත විධාන නාමයක් හෝ ෂෙල් කේතයක්. ඒ අනුව ඒවා විචල්යයක ගබඩා කිරීමේ විවිධ ක්රම තිබේ.
ඔබට විධාන නමක් තිබේ නම්, එය ගබඩා කර සුපුරුදු පරිදි ද්විත්ව උපුටා දැක්වීම් සහිත විචල්යය භාවිතා කරන්න.
command_path="$1"
…
"$command_path" --option --message="hello world"
ඔබට තර්ක සහිත විධානයක් තිබේ නම්, ගැටළුව ඉහත ගොනු නාම ලැයිස්තුවක් හා සමාන වේ: මෙය නූල් ලැයිස්තුවක් මිස නූලක් නොවේ. ඔබට තර්ක අතර ඇති අවකාශයන් සහිත තනි නූලකට දැමිය නොහැක, මන්ද ඔබ එසේ කරන්නේ නම්, තර්කවල කොටසක් වන අවකාශයන් සහ තර්ක වෙන් කරන අවකාශයන් අතර වෙනස ඔබට කිව නොහැක. ඔබේ කවචයේ අරා තිබේ නම්, ඔබට ඒවා භාවිතා කළ හැකිය.
cmd=(/path/to/executable --option --message="hello world" --)
cmd=("${cmd[@]}" "$file1" "$file2")
"${cmd[@]}"
ඔබ අරා නොමැතිව කවචයක් භාවිතා කරන්නේ නම් කුමක් කළ යුතුද? ස්ථානීය පරාමිතීන් වෙනස් කිරීමට ඔබට අවශ්ය නැතිනම් ඔබට තවමත් ස්ථානීය පරාමිතීන් භාවිතා කළ හැකිය.
set -- /path/to/executable --option --message="hello world" --
set -- "$@" "$file1" "$file2"
"$@"
ඔබට සංකීර්ණ ෂෙල් විධානයක් ගබඩා කිරීමට අවශ්ය නම්, උදා: යළි-යොමුවීම්, පයිප්ප ආදිය. හෝ ස්ථානීය පරාමිතීන් වෙනස් කිරීමට ඔබට අවශ්ය නැතිනම්? එවිට ඔබට විධානය අඩංගු නූලක් සෑදිය හැකි අතර, eval
බිල්ඩින් භාවිතා කරන්න .
code='/path/to/executable --option --message="hello world" -- /path/to/file1 | grep "interesting stuff"'
eval "$code"
අර්ථ දැක්වීමේදී කැදැලි උපුටා දැක්වීම් සැලකිල්ලට ගන්න code
: තනි උපුටා දැක්වීම් '…'
වචනාර්ථයෙන් සීමා කරයි, එවිට විචල්යයේ අගය code
නූල් /path/to/executable --option --message="hello world" -- /path/to/file1
වේ. මෙම eval
builtin එසේ එම අවස්ථාවේ දී මේ ආකාරයටම හා නළ මාර්ග, කියවූ ඇත ආදිය, එය කේත රචනය තුල පෙනී නම් කරන තර්කයක් ලෙස සම්මත වැල විග්රහ කළ කිරීමට ෂෙල් කියයි
භාවිතා eval
කිරීම උපක්රමශීලී ය. විග්රහ කරන විට කුමක් සිදුවේදැයි හොඳින් සිතා බලන්න. විශේෂයෙන්, ඔබට ගොනුවේ නමක් කේතයට ඇතුළත් කළ නොහැක: ඔබ එය උපුටා දැක්විය යුතුය, එය ප්රභව කේත ගොනුවක තිබුනාක් මෙන්. එය කිරීමට සෘජු ක්රමයක් නොමැත. වගේ දෙයක් code="$code $filename"
ගොනු නම නම් විරාම ඕනෑම ෂෙල් විශේෂ චරිතයක් (හිස් තැන්, අඩංගු වේ $
, ;
, |
, <
, >
, ආදිය). code="$code \"$filename\""
තවමත් කැඩී යයි "$\`
. පවා code="$code '$filename'"
විරාම ගොනු නම අඩංගු නම් '
. විසඳුම් දෙකක් තිබේ.
ගොනු නාමය වටා උපුටා දැක්වීම් තට්ටුවක් එක් කරන්න. එය කිරීමට ඇති පහසුම ක්රමය නම් එය වටා තනි උපුටා දැක්වීම් එකතු කිරීම සහ තනි උපුටා දැක්වීම් ආදේශ කිරීම ය '\''
.
quoted_filename=$(printf %s. "$filename" | sed "s/'/'\\\\''/g")
code="$code '${quoted_filename%.}'"
කේතය තුළ විචල්ය ප්රසාරණය තබා ගන්න, එවිට එය කේතය ඇගයීමට ලක් කරන විට මිස කේත කැබැල්ල ගොඩනඟන විට නොවේ. මෙය වඩාත් සරල නමුත් ක්රියාත්මක වන්නේ කේතය ක්රියාත්මක කරන අවස්ථාවේ විචල්යය එකම අගයක් සහිතව පවතී නම් පමණි, උදා: කේතය ලූපයකින් සාදා ඇත්නම් නොවේ.
code="$code \"\$filename\""
අවසාන වශයෙන්, ඔබට ඇත්ත වශයෙන්ම කේත අඩංගු විචල්යයක් අවශ්යද? කේත කොටසකට නමක් ලබා දිය හැකි වඩාත් ස්වාභාවික ක්රමය නම් ශ්රිතයක් අර්ථ දැක්වීම ය.
මොකද read
වෙන්නේ?
නොමැතිව -r
, read
අඛණ්ඩ රේඛා වලට ඉඩ දෙයි - මෙය තනි තාර්කික ආදාන රේඛාවකි:
hello \
world
read
ආදාන රේඛාව අක්ෂර වලින් වෙන් කරන ලද ක්ෂේත්ර වලට බෙදයි $IFS
(නොමැතිව -r
, බැක්ස්ලෑෂ් ද ඒවායින් ගැලවී යයි). උදාහරණයක් ලෙස, ආදාන වචන තුන අඩංගු රේඛාවක් වේ නම්, එවිට read first second third
සකසයි first
ආදාන පළමු වචනය, second
දෙවන වචනයක් හා third
තෙවන වචනය. තවත් වචන තිබේ නම්, අවසාන විචල්යයෙහි පෙර වචන සැකසීමෙන් පසු ඉතිරිව ඇති සියල්ල අඩංගු වේ. ප්රමුඛ හා පසුපස සුදු අවකාශය කපා ඇත.
IFS
හිස් නූලට සැකසීම කිසිදු කැපීමක් වළක්වයි. `IFS = වෙනුවට IFS = කියවීම` නිතර භාවිතා කරන්නේ ඇයිදැයි බලන්න ; කියවන අතරතුර..`? දිගු පැහැදිලි කිරීමක් සඳහා.
මොකක්ද වැරැද්ද xargs
?
ආදාන ආකෘතිය xargs
සුදු අවකාශයෙන් වෙන් කරන ලද නූල් වන අතර එය විකල්ප වශයෙන් තනි හෝ ද්විත්ව උපුටා දැක්විය හැකිය. සම්මත මෙවලමක් මෙම ආකෘතිය ප්රතිදානය නොකරයි.
ආදානය රේඛා ලැයිස්තුවක් xargs -L1
හෝ xargs -l
පාහේ වේ, නමුත් එතරම් නොවේ - රේඛාවක අවසානයේ ඉඩක් තිබේ නම්, පහත දැක්වෙන රේඛාව අඛණ්ඩ රේඛාවකි.
ඔබට xargs -0
අදාළ තැන භාවිතා කළ හැකිය (සහ ලබා ගත හැකි ස්ථාන: ග්නූ (ලිනක්ස්, සිග්වින්), බුසි බොක්ස්, බීඑස්ඩී, ඕඑස්එක්ස්, නමුත් එය පොසික්ස් හි නොමැත). එය ආරක්ෂිතයි, මන්ද බොහෝ දත්ත වල, විශේෂයෙන් ගොනු නාමවල ශුන්ය බයිට් දර්ශණය විය නොහැක. ශුන්යයෙන් වෙන් කරන ලද ගොනු නාම ලැයිස්තුවක් නිෂ්පාදනය කිරීම සඳහා, භාවිතා කරන්න find … -print0
(නැතහොත් find … -exec …
පහත විස්තර කර ඇති පරිදි ඔබට භාවිතා කළ හැකිය ).
සොයාගත් ලිපිගොනු සකසන්නේ find
කෙසේද?
find … -exec some_command a_parameter another_parameter {} +
some_command
බාහිර විධානයක් විය යුතුය, එය ෂෙල් ශ්රිතයක් හෝ අන්වර්ථයක් විය නොහැක. ලිපිගොනු සැකසීමට ඔබට කවචයක් කැඳවීමට අවශ්ය නම්, sh
පැහැදිලිව අමතන්න .
find … -exec sh -c '
for x do
… # process the file "$x"
done
' find-sh {} +
මට තවත් ප්රශ්නයක් තිබේ
මෙම වෙබ් අඩවියේ උපුටා දැක්වීමේ ටැගය බ්රවුස් කරන්න , නැතහොත් ෂෙල් හෝ ෂෙල්-ස්ක්රිප්ට් . (සාමාන්ය ඉඟි කිහිපයක් සහ අතින් තෝරාගත් පොදු ප්රශ්න ලැයිස්තුවක් බැලීමට “වැඩිදුර ඉගෙන ගන්න…” මත ක්ලික් කරන්න.) ඔබ සෙවූ නමුත් ඔබට පිළිතුරක් සොයාගත නොහැකි නම්, ඉවතට යන්න .
shellcheck
ඔබේ වැඩසටහන් වල ගුණාත්මකභාවය වැඩි දියුණු කිරීමට ඔබට උපකාරී වේ.