আমি কীভাবে ডিরেক্টরি ট্রি থেকে পুনরাবৃত্তভাবে কাজ করব এবং প্রতিটি ফাইলে একটি নির্দিষ্ট কমান্ড কার্যকর করব এবং পাথ, ফাইলের নাম, এক্সটেনশান, ফাইলসাইজ এবং কিছু অন্যান্য নির্দিষ্ট পাঠ্যকে ব্যাশের মধ্যে একটি ফাইলে আউটপুট করব।
আমি কীভাবে ডিরেক্টরি ট্রি থেকে পুনরাবৃত্তভাবে কাজ করব এবং প্রতিটি ফাইলে একটি নির্দিষ্ট কমান্ড কার্যকর করব এবং পাথ, ফাইলের নাম, এক্সটেনশান, ফাইলসাইজ এবং কিছু অন্যান্য নির্দিষ্ট পাঠ্যকে ব্যাশের মধ্যে একটি ফাইলে আউটপুট করব।
উত্তর:
find
সমাধানগুলি সহজ এবং শক্তিশালী হলেও , আমি আরও জটিল সমাধান তৈরি করার সিদ্ধান্ত নিয়েছি , যা এই আকর্ষণীয় ফাংশনের উপর ভিত্তি করে , যা আমি কয়েকদিন আগে দেখেছি।
1. এক্সিকিউটেবল স্ক্রিপ্ট ফাইল নামক তৈরি করুন walk
, যে অবস্থিত /usr/local/bin
শেল কমান্ড হিসাবে অ্যাক্সেস করা হবে:
sudo touch /usr/local/bin/walk
sudo chmod +x /usr/local/bin/walk
sudo nano /usr/local/bin/walk
nano
: Shift+ Insertপেস্টের জন্য; Ctrl+ Oএবং Enterসংরক্ষণের জন্য; Ctrl+ + Xপ্রস্থান জন্য।২. স্ক্রিপ্টের বিষয়বস্তুটি walk
হ'ল:
#!/bin/bash
# Colourise the output
RED='\033[0;31m' # Red
GRE='\033[0;32m' # Green
YEL='\033[1;33m' # Yellow
NCL='\033[0m' # No Color
file_specification() {
FILE_NAME="$(basename "${entry}")"
DIR="$(dirname "${entry}")"
NAME="${FILE_NAME%.*}"
EXT="${FILE_NAME##*.}"
SIZE="$(du -sh "${entry}" | cut -f1)"
printf "%*s${GRE}%s${NCL}\n" $((indent+4)) '' "${entry}"
printf "%*s\tFile name:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$FILE_NAME"
printf "%*s\tDirectory:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$DIR"
printf "%*s\tName only:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$NAME"
printf "%*s\tExtension:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$EXT"
printf "%*s\tFile size:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$SIZE"
}
walk() {
local indent="${2:-0}"
printf "\n%*s${RED}%s${NCL}\n\n" "$indent" '' "$1"
# If the entry is a file do some operations
for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
# If the entry is a directory call walk() == create recursion
for entry in "$1"/*; do [[ -d "$entry" ]] && walk "$entry" $((indent+4)); done
}
# If the path is empty use the current, otherwise convert relative to absolute; Exec walk()
[[ -z "${1}" ]] && ABS_PATH="${PWD}" || cd "${1}" && ABS_PATH="${PWD}"
walk "${ABS_PATH}"
echo
৩. ব্যাখ্যা:
walk()
তার উত্তরে জান্না দ্বারা ফাংশনটির মূল প্রক্রিয়াটি বেশ ভালভাবে বর্ণনা করা হয়েছে । সুতরাং আমি কেবল নতুন অংশটি বর্ণনা করব।
মধ্যে walk()
ফাংশন আমি এই লুপ জুড়েছেন:
for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
এর অর্থ প্রতিটি $entry
ফাইলের জন্য ফাংশনটি কার্যকর করা হবে file_specification()
।
ফাংশনটির file_specification()
দুটি অংশ রয়েছে। প্রথম অংশটি ফাইলের সাথে সম্পর্কিত ডেটা প্রাপ্ত করে - নাম, পথ, আকার ইত্যাদি The দ্বিতীয় অংশটি ভাল ফর্ম্যাটেড আকারে ডেটা আউটপুট দেয়। ডেটা ফর্ম্যাট করতে কমান্ড ব্যবহার করা হয় printf
। এবং আপনি যদি স্ক্রিপ্টটি টুইট করতে চান তবে আপনার এই আদেশটি পড়তে হবে - উদাহরণস্বরূপ এই নিবন্ধটি ।
ফাংশন file_specification()
ভাল জায়গা যেখানে আপনি লাগাতে পারেন নির্দিষ্ট কমান্ড প্রতিটি ফাইলের জন্য চালানো হবে । এই ফর্ম্যাটটি ব্যবহার করুন:
"$ {এন্ট্রি}" কমান্ড
অথবা আপনি কমান্ডের আউটপুটটিকে ভেরিয়েবল হিসাবে সংরক্ষণ করতে পারেন এবং তারপরে printf
এই পরিবর্তনশীল ইত্যাদি .:
MY_VAR = "$ ( কমান্ড) " {{এন্ট্রি} ")" printf "% * s s t ফাইলের আকার: \ t $ {YEL}% s {{এনসিএল} \ n" $ ((ইনডেন্ট + 4)) '' "$ MY_VAR"
বা সরাসরি printf
কমান্ডের আউটপুট:
printf "% * s s t ফাইলের আকার: \ t $ {YEL}% s {{এনসিএল} \ n" $ ((ইনডেন্ট + 4)) '' "$ ( কমান্ড " $ {এন্ট্রি} ")"
ভিক্ষাবৃত্তির অংশটিকে বলা হয়, আউটপুট সংগ্রহের জন্য কমান্ডের Colourise the output
মধ্যে ব্যবহৃত কয়েকটি ভেরিয়েবল আরম্ভ করুন printf
। এই সম্পর্কে আরও আপনি এখানে পেতে পারেন ।
স্ক্রিপের নীচে অতিরিক্ত শর্ত যুক্ত করা হয়েছে যা নিখুঁত এবং আপেক্ষিক পাথ নিয়ে কাজ করে।
৪. ব্যবহারের উদাহরণ:
walk
বর্তমান ডিরেক্টরি চালানোর জন্য:
walk # You shouldn't use any argument,
walk ./ # but you can use also this format
যে walk
কোনও শিশু ডিরেক্টরিতে চালানোর জন্য:
walk <directory name>
walk ./<directory name>
walk <directory name>/<sub directory>
walk
অন্য যে কোনও ডিরেক্টরিতে চালানোর জন্য:
walk /full/path/to/<directory name>
walk
আউটপুটের উপর ভিত্তি করে একটি পাঠ্য ফাইল তৈরি করতে :
walk > output.file
রঙ কোড ( উত্স ) ছাড়াই আউটপুট ফাইল তৈরি করতে :
walk | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" > output.file
5. ব্যবহারের বিক্ষোভ:
কেন কেউ এখনও এটি পোস্ট করেনি সে সম্পর্কে আমি কিছুটা বিভ্রান্ত হয়ে পড়েছি bash
, তবে আপনি যদি globstar
বিকল্পটি সক্ষম করেন এবং **
গ্লোব ব্যবহার করেন তবে প্রকৃতপক্ষে পুনরাবৃত্ত ক্ষমতা রয়েছে । এই হিসাবে, আপনি (প্রায়) খাঁটি bash
স্ক্রিপ্ট লিখতে পারেন যা এই জাতীয় পুনরাবৃত্তির গ্লোব স্টার ব্যবহার করে:
#!/usr/bin/env bash
shopt -s globstar
for i in ./**/*
do
if [ -f "$i" ];
then
printf "Path: %s\n" "${i%/*}" # shortest suffix removal
printf "Filename: %s\n" "${i##*/}" # longest prefix removal
printf "Extension: %s\n" "${i##*.}"
printf "Filesize: %s\n" "$(du -b "$i" | awk '{print $1}')"
# some other command can go here
printf "\n\n"
fi
done
লক্ষ্য করুন যে এখানে আমরা চাইলে ফাইলনামের অংশগুলি পেতে প্যারামিটার সম্প্রসারণ ব্যবহার করি এবং আমরা ফাইলের আকার du
এবং আউটপুট পরিষ্কারের ব্যতীত বাহ্যিক কমান্ডের উপর নির্ভর করি না awk
।
এবং এটি যেমন আপনার ডিরেক্টরি গাছকে অতিক্রম করে, আপনার আউটপুটটি এমন কিছু হওয়া উচিত:
Path: ./glibc/glibc-2.23/benchtests
Filename: sprintf-source.c
Extension: c
Filesize: 326
স্ক্রিপ্ট ব্যবহারের স্ট্যান্ডার্ড নিয়মগুলি প্রয়োগ করা হয়: এটি নিশ্চিত করে নিন যে এটি কার্যকর হয় chmod +x ./myscript.sh
এবং এটি বর্তমান ডিরেক্টরি থেকে এটি চালিয়ে যায় ./myscript.sh
বা এটি স্থাপন করে ~/bin
চালিত হয় source ~/.profile
।
"$(file "$i")"
(উপরের স্ক্রিপ্টে একটি প্রিন্টফের দ্বিতীয় অংশ হিসাবে) ফিরে আসবে?
output the path, filename, extension, filesize
, তাই উত্তর যা জিজ্ঞাসা করা হয়েছে তার সাথে মেলে। :)
আপনি ব্যবহার করতে পারেন find
কাজ করার
find /path/ -type f -exec ls -alh {} \;
আপনি যদি আকারের সাথে সমস্ত ফাইল তালিকাভুক্ত করতে চান তবে এটি আপনাকে সহায়তা করবে।
-exec
\;
একের পর এক ফাইল পার্স করার জন্য ব্যবহৃত প্রতিটি ফাইলের জন্য কাস্টম কমান্ড বা স্ক্রিপ্ট কার্যকর করতে আপনাকে অনুমতি দেবে
, আপনি +;
যদি সেগুলি বোঝাতে চান তবে আপনি ব্যবহার করতে পারেন (অর্থ ফাইলের নাম)।
সঙ্গে find
শুধুমাত্র।
find /path/ -type f -printf "path:%h fileName:%f size:%kKB Some Text\n" > to_single_file
অথবা, আপনি নীচে পরিবর্তে ব্যবহার করতে পারেন:
find -type f -not -name "to_single_file" -execdir sh -c '
printf "%s %s %s %s Some Text\n" "$PWD" "${1#./}" "${1##*.}" $(stat -c %s "$1")
' _ {} \; > to_single_file
find -printf
)। +1
আপনি যদি গাছটি কত গভীর তা জানেন তবে সবচেয়ে সহজ উপায় হ'ল ওয়াইল্ডকার্ড ব্যবহার করা *
।
শেল স্ক্রিপ্ট বা ফাংশন হিসাবে আপনি যা করতে চান তা লিখুন
function thing() { ... }
তারপরে দৌড়াও for i in *; do thing "$i"; done
, for i in */*; do thing "$i"; done
ইত্যাদি ...
আপনার ফাংশন / স্ক্রিপ্টের মধ্যে, আপনি যে ফাইলগুলির সাথে কাজ করতে চান তার একক আউট তৈরি করতে এবং সেগুলির সাথে আপনার যা যা প্রয়োজন তা করতে কিছু সাধারণ পরীক্ষা ব্যবহার করতে পারেন ।
$i
।
for i in */*
কাজ করে। এখানে এটি পরীক্ষা করুন:for i in */*; do printf "|%s|\n" "$i"; done
find
এটি করতে পারেন:
find ./ -type f -printf 'Size:%s\nPath:%H\nName:%f\n'
কটাক্ষপাত আছে man find
অন্যান্য ফাইল বৈশিষ্ট্যের জন্য।
আপনার যদি সত্যিই এক্সটেনশনের প্রয়োজন হয় তবে আপনি এটি যুক্ত করতে পারেন:
find ./ -type f -printf 'Size:%s\nPath:%H\nName:%f\nExtension:' -exec sh -c 'echo "${0##*.}\n"' {} \;