اول و پیش از همه برای درک آنکه چرا مشکل دارید، مبحث شناسهها را بخوانید، تا خوب دریابید، پوسته جملاتی را که به آن میدهید چطور میفهمد. اگر میخواهید هر کاری با شل انجام بدهید، واجب است که شما درک خوبی از این موضوع کسب نمایید.
شیوه برگزیده کار با نامهای انتخابی فایل، بازهم استفاده از find(1) میباشد:
find ... -exec command {} \;
یا، اگر به مدیریت نامفایلها به طور دسته جمعی نیاز دارید:
find ... -exec command {} +
xargs به ندرت بتواند سودمندتر از مورد فوق باشد، اما اگر شما حقیقتاً اصرار دارید، استفاده از -0 را به خاطر داشته باشید:
# نیاز دارد GNU/BSD درfind و xargs به فرمان find ... -print0 | xargs -0 command # استفاده نکنید xargs هرگز بدون گزینه 0- یا ضمائم مشابه از
یکی از اینها را به کار ببرید مگر اینکه واقعاً نمیتوانید.
روش دیگر برای کار با فایلهایی که در نامشان دارای فاصله میباشند استفاده از بسط نام فایل پوسته(globbing) است. اشکال آن، کار نکردن به طور بازگشتی است(به استثنای بسطهای zsh یا globstar نگارش 4 از bash)، اما اگر شما فقط نیاز به پردازش تمام فایلهای یک دایرکتوری منفرد دارید، به طور خارقالعادهای خوب کار میکند.
برای مثال، این کُد تمام فایلهای *.mp3 در دایرکتوری فعلی را با جایگزینی خطزیر(underscore) به جای فاصله در نامشان تغییر نام میدهد:
# Bash/ksh for file in ./*\ *.mp3; do mv "$file" "${file// /_}" done
برای مثالهای بیشتر تغییر نام فایلها، پرسش و پاسخ شماره 30 را ملاحظه نمایید.
به خاطر داشته باشید، لازم است شماتمام بسطهای پارامتر را با استفاده از نقلقول دوگانه نقلقولی کنید. اگر چنین نکنید، بسط تحت تأثیر تفکیک کلمه قرار میگیرد(همچنین بخش جداسازی شناسه و تلههایBash را ببینید). همچنین، همیشه جانشینها را با "./" پیشوند کنید، در غیر این صورت، اگر فایلی با نام شامل "-" به عنوان اولین کاراکتر نام وجود داشته باشد بسطها ممکن است به طور غلط، به عنوان گزینه تفسیر گردند.
یک روش دیگر کار با نام فایلها به طور بازگشتی، شامل استفاده از گزینه -print0 فرمان find (الحاقیه GNU/BSD )، همراه با گزینه -d پوسته bash برای read میباشد:
# Bash unset a i while IFS= read -r -d $'\0' file; do a[i++]="$file" # or however you want to process each file done < <(find /tmp -type f -print0)
مثال اسبق تمام فایلهای دایرکتوری /tmp را (به طور بازگشتی) در یک آرایه حتی اگر در نام آنها سطرجدید یا فضای سفید موجود باشد، میخواند، از طریقِ اجبار read به استفاده از بایت تهی(\0) به عنوان جداکننده سطر. چون NUL بایت معتبر در نام فایل یونیکس نمیباشد، این رویکرد در کنار استفاده از find -exec مطمئنترین روش است. IFS= برای اجتناب از بریدن فضای سفید ابتدا و انتها لازم است، و -r برای اجتناب از پردازش کاراکتر
# Bash unset a i while IFS= read -r -d '' file; do a[i++]="$file" done < <(find /tmp -type f -print0)
پس چرا این کار نمیکند؟
# کار نمیکند unset a i find /tmp -type f -print0 | while IFS= read -r -d '' file; do a[i++]="$file" done
به علت وجود لوله، تمامیت حلقه while در یک پوسته فرعی انجام میشود و بنابراین تخصیصهای آرایه پس از خاتمه یافتن حلقه از دست خواهد رفت. (برای جزئیات بیشتر در این باره، پرسش و پاسخ شماره 24 را ملاحظه کنید.)
پرسش و پاسخ 20 (آخرین ویرایش 2012-06-29 11:53:50 توسط GreyCat)