ডিরেক্টরি কাঠামোতে প্রতিটি ফাইল সম্পর্কে তথ্য সংগ্রহ করতে পুনরাবৃত্তাকার বাশ স্ক্রিপ্ট


14

আমি কীভাবে ডিরেক্টরি ট্রি থেকে পুনরাবৃত্তভাবে কাজ করব এবং প্রতিটি ফাইলে একটি নির্দিষ্ট কমান্ড কার্যকর করব এবং পাথ, ফাইলের নাম, এক্সটেনশান, ফাইলসাইজ এবং কিছু অন্যান্য নির্দিষ্ট পাঠ্যকে ব্যাশের মধ্যে একটি ফাইলে আউটপুট করব।


হ্যাঁ, সম্পাদনার জন্য ধন্যবাদ; আমি প্রথম বিষয়গুলিকে অতিমাত্রায় স্বীকার করব, কারণ আমাকে হুমান বিশ্বের 800 টি অপ্রাসঙ্গিক প্রশ্ন জিজ্ঞাসা করা হয়েছে; সুতরাং আমি প্রশ্নগুলিতে সুস্পষ্ট উত্তর দেওয়ার চেষ্টা করি; আমি যদিও শিখব :-)
স্পোকইনিএসএস

1
ঠিক আছে, আমি মনে করি প্রশ্নটি কী করা উচিত সে সম্পর্কে পুরোপুরি পরিষ্কার, প্রতিটি ফাইল সম্পর্কে ডিরেক্টরি ট্রি এবং আউটপুট তথ্য দিয়ে যান। প্রশ্নটি বেশ পরিষ্কার, এবং ইতিমধ্যে উত্তর পরিমাণ বিচার করে, মানুষ এটি মোটামুটি ভালভাবে বুঝতে পারে understand অস্পষ্ট হওয়ার জন্য তিনটি ভোট সত্যই এই প্রশ্নের প্রাপ্য নয়
সের্গেই কলডিয়াজহনি

উত্তর:


16

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. ব্যবহারের বিক্ষোভ:

এখানে চিত্র বর্ণনা লিখুন


এটি পুরোপুরি কাজ, তবে ভাল দেখাচ্ছে। সাবাশ !
সের্গেই কোলডিয়াজহনি

এই জিআইএফগুলি তৈরি করতে আপনি কী প্রক্রিয়া ব্যবহার করছেন @ pa4080?
pbhj

@ পিবিএজেজে, উবুন্টু-এর অধীনে আমি পিক ব্যবহার করছি এটি সহজ এবং দুর্দান্ত, তবে কখনও কখনও ক্র্যাশ হয় এবং সম্পাদনার ক্ষমতা থাকে না। আমার বেশিরভাগ জিআইএফগুলি উইন্ডোজের আওতায় তৈরি করা হয়েছে, যেখানে আমি ভিএনসি সংযোগের উইন্ডোটি রেকর্ড করছি। আমার একটি পৃথক ডেস্কটপ মেশিন রয়েছে যা মূলত আমি এমএস অফিস এবং জিআইএফ তৈরির জন্য ব্যবহার করি :) আমি যে সরঞ্জামটি সেখানে ব্যবহার করছি সেগুলি স্ক্রিনটোজিফ । এটি ওপেনসোর্স, ফ্রি এবং শক্তিশালী সম্পাদক এবং প্রসেসিং মেকানিসাম রয়েছে। দুর্ভাগ্যক্রমে আমি উবুন্টুর জন্য স্ক্রিনটোজিফের মতো সরঞ্জাম খুঁজে পাচ্ছি না।
pa4080

13

কেন কেউ এখনও এটি পোস্ট করেনি সে সম্পর্কে আমি কিছুটা বিভ্রান্ত হয়ে পড়েছি 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")"(উপরের স্ক্রিপ্টে একটি প্রিন্টফের দ্বিতীয় অংশ হিসাবে) ফিরে আসবে?
pbhj

1
@pbhj আমার কাছে ব্যক্তিগতভাবে? কিছুই নেই। তবে ওপি যারা প্রশ্ন জিজ্ঞাসা করেছিল output the path, filename, extension, filesize , তাই উত্তর যা জিজ্ঞাসা করা হয়েছে তার সাথে মেলে। :)
সের্গেই কলডিয়াজনি

12

আপনি ব্যবহার করতে পারেন findকাজ করার

find /path/ -type f -exec ls -alh {} \;

আপনি যদি আকারের সাথে সমস্ত ফাইল তালিকাভুক্ত করতে চান তবে এটি আপনাকে সহায়তা করবে।

-exec\;একের পর এক ফাইল পার্স করার জন্য ব্যবহৃত প্রতিটি ফাইলের জন্য কাস্টম কমান্ড বা স্ক্রিপ্ট কার্যকর করতে আপনাকে অনুমতি দেবে , আপনি +;যদি সেগুলি বোঝাতে চান তবে আপনি ব্যবহার করতে পারেন (অর্থ ফাইলের নাম)।


এটি দুর্দান্ত, কিন্তু ওপিতে উল্লিখিত সমস্ত প্রয়োজনীয়তার উত্তর দেয় না।
সнιη

1
@ .sнιη আমি তাকে কাজ করার জন্য একটি টেম্পলেট দিয়েছি। আমি জানি, এটি এই প্রশ্নের সম্পূর্ণ উত্তর নয়, কারণ আমি মনে করি প্রশ্নটি নিজেই বিস্তৃত।
রাজেশ রাজেন্দ্রন

6

সঙ্গে 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

2
মার্জিত এবং সহজ (আপনি যদি জানেন তবে find -printf)। +1
ডেভিড ফোস্টার 13

1

আপনি যদি গাছটি কত গভীর তা জানেন তবে সবচেয়ে সহজ উপায় হ'ল ওয়াইল্ডকার্ড ব্যবহার করা *

শেল স্ক্রিপ্ট বা ফাংশন হিসাবে আপনি যা করতে চান তা লিখুন

function thing() { ... }

তারপরে দৌড়াও for i in *; do thing "$i"; done, for i in */*; do thing "$i"; doneইত্যাদি ...

আপনার ফাংশন / স্ক্রিপ্টের মধ্যে, আপনি যে ফাইলগুলির সাথে কাজ করতে চান তার একক আউট তৈরি করতে এবং সেগুলির সাথে আপনার যা যা প্রয়োজন তা করতে কিছু সাধারণ পরীক্ষা ব্যবহার করতে পারেন ।


"আপনার ফাইলের নামের কোনওটিতে ফাঁকা থাকলে এটি কাজ করবে না" ... কারণ আপনি আপনার ভেরিয়েবলগুলি উদ্ধৃত করতে ভুলে গেছেন! এর পরিবর্তে "$ i" ব্যবহার করুন $i
مورু

@ মুরু না, এটি কাজ না করার কারণটি হ'ল "জন্য" ফাঁকা জায়গাগুলিতে বিভাজন - " / 'সমস্ত ফাইলের স্পেস-বিভাজিত তালিকায় প্রসারিত হয় this আপনি এটিকে ঘিরে কাজ করতে পারেন, যেমন আইএফএসের সাথে জগাখিচির মাধ্যমে, তবে এই মুহুর্তে আপনি সম্ভবত
সন্ধানটি

@ pa4080 এই উত্তরের সাথে প্রাসঙ্গিক নয়, তবে এটি যেভাবেই দুর্দান্ত কার্যকর দেখায়, ধন্যবাদ!
বেনুবার্ড

আমি মনে করি আপনি বুঝতে পারছেন না কীভাবে for i in */*কাজ করে। এখানে এটি পরীক্ষা করুন:for i in */*; do printf "|%s|\n" "$i"; done
মুরু

এখানে উদ্ধৃতি চিহ্নের গুরুত্বের একটি প্রমাণ দেওয়া হয়েছে: i.stack.imgur.com/oYSj2.png
pa4080

1

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"' {} \;
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.