ගැටලුව වන්නේ
for f in $(find .)
නොගැලපෙන කරුණු දෙකක් ඒකාබද්ධ කරයි.
find
නව රේඛා අක්ෂර මගින් වෙන් කරන ලද ගොනු මාර්ග ලැයිස්තුවක් මුද්රණය කරයි. $(find .)
එම ලැයිස්තු සන්දර්භය තුළ ඔබ සඳහන් නොකළ විට එය කැඳවනු ලබන භේදය + ග්ලෝබ් ක්රියාකරු $IFS
(පෙරනිමියෙන් නව රේඛාව පමණක් නොව අවකාශය සහ ටැබ් (සහ එන්.යූ.එල් zsh
) ද ඇතුළත් වේ. in zsh
) (සහ ksh93 හෝ pdksh ව්යුත්පන්නයන්හි වරහන් ප්රසාරණය පවා!).
ඔබ එය සෑදුවත්:
IFS='
' # split on newline only
set -o noglob # disable glob (also disables brace expansion in pdksh
# but not ksh93)
for f in $(find .) # invoke split+glob
නව රේඛා අක්ෂරය ගොනු මාර්ගයක ඇති තරම් වලංගු බැවින් එය තවමත් වැරදිය. ප්රතිදානය find -print
හුදෙක් විශ්වාසදායක ලෙස පශ්චාත් සැකසුම් කළ නොහැකි ය ( මෙහි පෙන්වා ඇති පරිදි සමහර කැටි ගැසුණු උපක්රම භාවිතා කිරීමෙන් හැර ).
එහි අර්ථය වන්නේ කවචයට ප්රතිදානය find
සම්පුර්ණයෙන්ම ගබඩා කළ යුතු අතර , පසුව ලිපිගොනු විවර කිරීමට පෙර එය බෙදන්න + ග්ලෝබ් කරන්න (එයින් අදහස් කරන්නේ එම ප්රතිදානය දෙවන වරටත් මතකයේ ගබඩා කිරීමයි).
find . | xargs cmd
සමාන ගැටළු ඇති බව සලකන්න (එහි, හිස්, නව රේඛාව, තනි උපුටා දැක්වීම, ද්විත්ව උපුටා දැක්වීම සහ බැක්ස්ලෑෂ් (සහ සමහර xarg
ක්රියාත්මක කිරීම් සමඟ බයිට් වලංගු අක්ෂරවල කොටසක් නොවීම) ගැටළුවක් වේ)
වඩාත් නිවැරදි විකල්ප
එකක් භාවිතා කිරීමට ඇති එකම මාර්ගය වන for
ප්රතිදානය මත ලූප find
භාවිතා කිරීමට වනු ඇත zsh
සහය දැක්වීම IFS=$'\0'
සහ:
IFS=$'\0'
for f in $(find . -print0)
(ආදේශ -print0
සමග -exec printf '%s\0' {} +
සඳහා find
අද කාලයේ නොවන සම්මත (නමුත් ඉතා පොදු සහාය දෙන බව) නැහැ නිර්මාණයන් -print0
).
මෙන්න, නිවැරදි හා අතේ ගෙන යා හැකි ක්රමය භාවිතා කිරීම -exec
:
find . -exec something with {} \;
නැතහොත් something
තර්ක එකකට වඩා ගත හැකි නම් :
find . -exec something with {} +
ඔබට එම ලිපිගොනු ලැයිස්තුව ෂෙල් එකකින් හැසිරවීමට අවශ්ය නම්:
find . -exec sh -c '
for file do
something < "$file"
done' find-sh {} +
(පරෙස්සම් වන්න එය එකකට වඩා ආරම්භ විය හැක sh
).
සමහර පද්ධති වල, ඔබට මෙය භාවිතා කළ හැකිය:
find . -print0 | xargs -r0 something with
ඇති සාමාන්ය වාක්ය රීති හා මාධ්යයන් මත කුඩා වාසිය නමුත් something
ගේ stdin
එක්කෝ නල හෝ /dev/null
.
ඔබට එය භාවිතා කිරීමට අවශ්ය විය හැකි එක් හේතුවක් වන්නේ සමාන්තර සැකසුම් සඳහා -P
GNU විකල්පය භාවිතා කිරීමයි xargs
. මෙම stdin
ප්රශ්නය ද GNU සමග පමණ වැඩ කළ හැකි xargs
සමග -a
ෂෙල් වෙඩි ක්රියාවලිය ආදේශන සහාය සමඟ විකල්පය:
xargs -r0n 20 -P 4 -a <(find . -print0) something
නිදසුනක් ලෙස, something
ගොනු තර්ක 20 ක් ගන්නා එක් එක් සමගාමී ආයාචනා 4 ක් දක්වා ධාවනය කිරීම .
සමඟ zsh
හෝ bash
, ප්රතිදානයට වඩා ලූපයක් ලබා ගත හැකි තවත් ක්රමයක් find -print0
වන්නේ:
while IFS= read -rd '' file <&3; do
something "$file" 3<&-
done 3< <(find . -print0)
read -d ''
නව රේඛා වෙන්කර ඇති ඒවා වෙනුවට NUL වෙන් කළ වාර්තා කියවයි.
bash-4.4
සහ ඊට ඉහළින් ඇති ලිපිගොනු find -print0
අරාවකින් ගබඩා කළ හැකිය :
readarray -td '' files < <(find . -print0)
මෙම zsh
සමාන (ආරක්ෂා කර ගැනීමේ වාසිය ඇති find
පිටවීමේ තත්ත්වය 's):
files=(${(0)"$(find . -print0)"})
සමඟ zsh
, ඔබට බොහෝ find
ප්රකාශන ග්ලෝබ් සුදුසුකම් සහිත පුනරාවර්තන ග්ලෝබිං සංයෝජනයකට පරිවර්තනය කළ හැකිය . නිදසුනක් ලෙස, ලිහිල් කිරීම find . -name '*.txt' -type f -mtime -1
වනුයේ:
for file (./**/*.txt(ND.m-1)) cmd $file
හෝ
for file (**/*.txt(ND.m-1)) cmd -- $file
(අවශ්යතාවය පරෙස්සම් --
සමග මෙන් **/*
, ගොනු මාර්ග සමඟ ආරම්භ නොමැත ./
, ඒ සමඟ ආරම්භ කළ හැක -
උදාහරණයක්).
ksh93
හා bash
අවසානයේ සඳහා සහය එක් **/
(වැඩි ආවර්තනික globbing ආකාර අත්තිකාරම් ඇතත්), නමුත් භාවිතය වන පරිදි තවමත් glob සුදුසුකම් නොමැති **
ඉතා එහි සීමා විය. bash
4.3 ට පෙර ඩිරෙක්ටරි ගසෙන් බැසීමේදී සිම්ලින්ක් අනුගමනය කරන බවට පරිස්සම් වන්න .
පෙරළීම සඳහා මෙන් $(find .)
, එයින් අදහස් වන්නේ මතක ගොනු 1 හි ඇති මුළු ගොනු ලැයිස්තුවම ගබඩා කිරීමයි . සමහර අවස්ථාවලදී ලිපිගොනු පිළිබඳ ඔබේ ක්රියාවන් ලිපිගොනු සොයා ගැනීම කෙරෙහි බලපෑමක් ඇති කිරීමට ඔබ අකමැති වුවද එය යෝග්ය වේ (ඔබ සොයාගත හැකි තවත් ලිපිගොනු එකතු කරන විට වැනි).
වෙනත් විශ්වසනීයත්වය / ආරක්ෂක කරුණු
තරඟ කොන්දේසි
දැන්, අපි විශ්වසනීයත්වය ගැන කතා කරන්නේ නම්, කාලය find
/ ධාවන zsh
ගොනුව සොයා ගැනීම සහ එය නිර්ණායක හා එය භාවිතා කරන වේලාව ( TOCTOU race ) අතර ඇති ධාවන කොන්දේසි සඳහන් කළ යුතුය.
ඩිරෙක්ටරි ගසකින් බැසීමේදී පවා, සිම්ලින්ක් අනුගමනය නොකිරීමට වග බලා ගත යුතු අතර TOCTOU තරඟයකින් තොරව එය කළ යුතුය. find
( find
අවම වශයෙන් GNU ) එය කරන්නේ openat()
නිවැරදි O_NOFOLLOW
ධජ භාවිතා කරමින් නාමාවලි විවෘත කිරීමෙන් (සහය දක්වන තැන) සහ එක් එක් නාමාවලිය සඳහා ගොනු විස්තරයක් විවෘතව තබා ගැනීමෙන් zsh
/ bash
/ ksh
එසේ නොකරන්න. එබැවින් ප්රහාරකයෙකුට නියම වේලාවට නාමාවලියක් සිම්ලින්ක් සමඟ ප්රතිස්ථාපනය කිරීමට හැකි වූ විට, ඔබට වැරදි නාමාවලියෙන් බැස යා හැකිය.
find
නාමාවලිය නිසියාකාරව බැස ගියත් , -exec cmd {} \;
ඊටත් වඩා වැඩි ගණනක් -exec cmd {} +
එක් වරක් cmd
ක්රියාත්මක කළත් , නිදසුනක් ලෙස cmd ./foo/bar
හෝ cmd ./foo/bar ./foo/bar/baz
කාලය cmd
භාවිතා කරන විට ./foo/bar
, ගුණාංග bar
තවදුරටත් ගැලපෙන නිර්ණායක සපුරාලන්නේ නැත find
, නමුත් ඊටත් වඩා නරක ./foo
විය හැකිය. වෙනත් යම් ස්ථානයක් වෙත symlink වෙනුවට (සහ ජාතිය කවුළුව සමග ගොඩක් විශාල කර ඇත -exec {} +
එහිදී find
බොත්තමක් ඔබා එය කතා කිරීමට තරම් ගොනු කිරීමට cmd
).
සමහර find
ක්රියාවට -execdir
නැංවීමේදී (සම්මත නොවන) දෙවන ගැටළුව සමනය කිරීම සඳහා පුරෝකථනයක් ඇත.
සමඟ:
find . -execdir cmd -- {} \;
find
chdir()
ක්රියාත්මක වීමට පෙර ගොනුවේ මව් නාමාවලියට cmd
. ඇමතීම වෙනුවට cmd -- ./foo/bar
, එය අමතයි cmd -- ./bar
( cmd -- bar
සමහර ක්රියාත්මක කිරීම් සමඟ, එබැවින් --
), එබැවින් ./foo
සිම්ලින්ක් වෙත වෙනස් කිරීමේ ගැටළුව මඟහරවා ගත හැකිය. එමඟින් rm
ආරක්ෂිත වැනි විධානයන් භාවිතා කරයි (එයට තවමත් වෙනත් ගොනුවක් ඉවත් කළ හැකිය, නමුත් වෙනත් නාමාවලියක ඇති ගොනුවක් නොවේ), නමුත් සමමුහුර්ත අනුගමනය නොකිරීමට සැලසුම් කර ඇත්නම් මිස ගොනු වෙනස් කළ හැකි විධාන නොවේ.
-execdir cmd -- {} +
සමහර විට ද ක්රියා කරන නමුත් GNU find
හි සමහර අනුවාදයන් ඇතුළු ක්රියාත්මක කිරීම් කිහිපයක් සමඟ එය සමාන වේ -execdir cmd -- {} \;
.
-execdir
ඉතා ගැඹුරු නාමාවලි ගස් හා සම්බන්ධ සමහර ගැටලු සමඟ කටයුතු කිරීමේ වාසිය ද ඇත.
තුළ:
find . -exec cmd {} \;
ලබා දී ඇති මාවතේ ප්රමාණය cmd
ගොනුව ඇති ඩිරෙක්ටරියේ ගැඹුර සමඟ වර්ධනය වේ. එම ප්රමාණය PATH_MAX
(ලිනක්ස් හි 4k වැනි) වඩා විශාල cmd
වුවහොත්, එම මාර්ගයේ සිදුවන ඕනෑම පද්ධති ඇමතුමක් ENAMETOOLONG
දෝෂයකින් අසමත් වේ .
සමඟ -execdir
, ගොනුවේ නම පමණක් (සමහර විට උපසර්ගය සහිතව ./
) ලබා දෙනු cmd
ලැබේ. බොහෝ ගොනු පද්ධතිවල ඇති ගොනු නම් වලට වඩා අඩු සීමාවක් ( NAME_MAX
) ඇත PATH_MAX
, එබැවින් ENAMETOOLONG
දෝෂය ඇතිවීමට ඇති ඉඩකඩ අඩුය.
බයිට්ස් එදිරිව අක්ෂර
බොහෝ විට find
යුනික්ස් වැනි පද්ධති වල ගොනු නාමයන් බයිට් අනුක්රමයකි (ඕනෑම බයිට් අගයක් නමුත් ගොනු මාර්ගයක 0, සහ බොහෝ පද්ධතිවල) (සාමාන්යයෙන් ගොනු නාම හැසිරවීමේදී) ආරක්ෂාව ගැන සැලකිලිමත් වන විට බොහෝ විට නොසලකා හරිනු ලැබේ. ASCII මත පදනම් වූ ඒවා, අපි දැනට දුර්ලභ EBCDIC පදනම් කරගත් ඒවා නොසලකා හරිනු ඇත) 0x2f යනු මාර්ගය පරිසීමකය).
එම බයිට් පෙළ ලෙස සලකා බැලීමට අවශ්ය දැයි තීරණය කිරීම යෙදුම් සතු ය. ඔවුන් සාමාන්යයෙන් එසේ කරයි, නමුත් සාමාන්යයෙන් බයිට් වලින් අක්ෂර වලට පරිවර්තනය කිරීම පරිශීලකයාගේ ස්ථානය මත පදනම්ව පරිසරය මත පදනම් වේ.
එහි තේරුම නම්, ලබා දී ඇති ගොනු නාමයකට පෙදෙසි අනුව වෙනස් පෙළ නිරූපණයක් තිබිය හැකිය. නිදසුනක් ලෙස, බයිට් අනුක්රමය 63 f4 74 e9 2e 74 78 74
වනුයේ côté.txt
අක්ෂර කට්ටලය ISO-8859-1 cєtщ.txt
වන පෙදෙසක එම ලිපිගොනු නාමය අර්ථ නිරූපණය කරන යෙදුමක් සඳහා වන අතර ඒ වෙනුවට අක්ෂර කට්ටලය IS0-8859-5 වේ.
වඩාත් නරක ය. අක්ෂර කට්ටලය යූටීඑෆ් -8 (වර්තමානයේ සාමාන්යය) ඇති ප්රදේශයක, 63 f4 74 e9 2e 74 78 74 අක්ෂරවලට අනුරූපණය කළ නොහැක!
find
ගොනු නාම එහි -name
/ -path
අනාවැකි සඳහා පෙළක් ලෙස සලකන එවැනි යෙදුමකි (සහ තවත්, සමහර ක්රියාත්මක කිරීම් වැනි -iname
හෝ වැඩි ගණනක් -regex
).
එහි තේරුම නම්, උදාහරණයක් ලෙස, find
ක්රියාත්මක කිරීම් කිහිපයක් සමඟ (GNU ද ඇතුළුව find
).
find . -name '*.txt'
63 f4 74 e9 2e 74 78 74
යූටීඑෆ් -8 පෙදෙසක *
( අක්ෂර 0 හෝ ඊට වැඩි ගණනක් ගැලපෙන , බයිට් නොව) එම අක්ෂර නොවන අක්ෂර සමඟ නොගැලපෙන බැවින් ඉහත අපගේ ගොනුව සොයාගත නොහැකි වනු ඇත .
LC_ALL=C find...
සී පෙදෙසි අක්ෂරයකට එක් බයිට් එකක් අදහස් කරන අතර (සාමාන්යයෙන්) සියලු බයිට් අගයන් අක්ෂරයකට සිතියම් ගත කරන බවට සහතික වන බැවින් (සමහර බයිට් අගයන් සඳහා නිර්වචනය නොකළ ඒවා විය හැක).
දැන් එම ලිපිගොනු ෂෙල් එකකින් ලූප කිරීම ගැන කතා කරන විට, එම බයිට් එදිරිව අක්ෂරය ද ගැටළුවක් විය හැකිය. අපි සාමාන්යයෙන් ප්රධාන ෂෙල් වෙඩි 4 ක් දකිමු:
තවමත් බහු-බයිට් නොදන්නා අය වැනි dash
. ඔවුන් සඳහා, බයිට් අක්ෂරයකට සිතියම් ගත කරයි. උදාහරණයක් ලෙස, UTF-8 හි côté
අක්ෂර 4 ක් ඇත, නමුත් බයිට් 6 කි. යූටීඑෆ් -8 අක්ෂර වින්යාසය ඇති පෙදෙසක, දී
find . -name '????' -exec dash -c '
name=${1##*/}; echo "${#name}"' sh {} \;
find
යූටීඑෆ් -8 හි කේතනය කර ඇති අක්ෂර 4 කින් සමන්විත ලිපිගොනු සාර්ථකව සොයාගනු ඇත, නමුත් dash
දිග 4 ත් 24 ත් අතර දිග වාර්තා කරයි.
yash
: ප්රතිවිරුද්ධ. එය ගනුදෙනු කරන්නේ චරිත සමඟ පමණි . එය ගන්නා සියලුම ආදාන අභ්යන්තරව අක්ෂර වලට පරිවර්තනය වේ. එය වඩාත් ස්ථාවර කවචයක් සාදයි, නමුත් එයින් අදහස් කරන්නේ එයට අත්තනෝමතික බයිට් අනුක්රමයන් (වලංගු අක්ෂර වලට පරිවර්තනය නොකරන) සමඟ කටයුතු කළ නොහැකි බවයි. සී පෙදෙසෙහි වුවද, 0x7f ට වඩා වැඩි බයිට් අගයන් සමඟ කටයුතු කළ නොහැක.
find . -exec yash -c 'echo "$1"' sh {} \;
côté.txt
උදාහරණයක් ලෙස UTF-8 පෙදෙසක අපගේ ISO-8859-1 මත අසමත් වනු ඇත .
බහු-බයිට් සහාය ක්රමයෙන් එකතු කර ඇති bash
හෝ කැමති අය zsh
. ඒවා අක්ෂර ලෙස සිතියම් ගත කළ නොහැකි බයිට් සලකා බැලීමට නැවත වැටෙනු ඇත. GBK හෝ BIG5-HKSCS වැනි අඩු බහු-බයිට් අක්ෂර කට්ටල සමඟ ඔවුන් සතුව තවමත් දෝෂ කිහිපයක් තිබේ (ඒවායේ බහු-බයිට් අක්ෂර 0-127 පරාසය තුළ (ASCII අක්ෂර වැනි) බයිට් අඩංගු බැවින් ඒවා ඉතා අශෝභන වේ. ).
වගේ අය sh
(අවම වශයෙන් 11) ඒ අතරින් කිහිපයකි හෝ mksh -o utf8-mode
සහාය ලබා දෙන නමුත්, UTF-8 සඳහා පමණක් බහු-බයිට්.
සටහන්
1 සම්පූර්ණත්වය සඳහා, zsh
සම්පූර්ණ ලැයිස්තුවම මතකයේ ගබඩා නොකර පුනරාවර්තන ග්ලෝබින් භාවිතයෙන් ලිපිගොනු ලූපයක් බවට පත්කිරීමේ ක්රමයක් අපට සඳහන් කළ හැකිය :
process() {
something with $REPLY
false
}
: **/*(ND.m-1+process)
+cmd
යනු cmd
වර්තමාන ගොනු මාර්ගය සමඟ (සාමාන්යයෙන් ශ්රිතයක්) කැඳවන ග්ලෝබ් සුදුසුකම්යකි $REPLY
. ගොනුව තෝරා ගත යුතුද යන්න තීරණය කිරීම සඳහා ශ්රිතය සත්ය හෝ අසත්යය ලබා දෙයි (තවද අරාවෙහි ඇති $REPLY
ගොනු කිහිපයක් වෙනස් කිරීමට හෝ ආපසු ලබා දීමටද පුළුවන $reply
). මෙන්න අපි එම ශ්රිතයේ සැකසුම් සිදු කර අසත්යය නැවත ලබා දෙන්නෙමු එවිට ගොනුව තෝරා නොගනී.