निर्देशिका संरचना में प्रत्येक फ़ाइल के बारे में जानकारी एकत्र करने के लिए पुनरावर्ती बैश स्क्रिप्ट


14

मैं एक निर्देशिका ट्री के माध्यम से पुनरावर्ती रूप से कैसे काम करता हूं और प्रत्येक फ़ाइल पर एक विशिष्ट कमांड निष्पादित करता हूं, और बैश में एकल फ़ाइल के लिए पथ, फ़ाइल नाम, एक्सटेंशन, फ़ाइलों और कुछ अन्य विशिष्ट पाठ को आउटपुट करता हूं।


योग्य, संपादन के लिए धन्यवाद; मैं चीजों को स्वीकार करने वाला पहला व्यक्ति होऊंगा, क्योंकि मैं हुमन की दुनिया में 800 अप्रासंगिक सवाल पूछ रहा था; इसलिए मैं सवालों में स्पष्ट लोगों का जवाब देने की कोशिश करता हूं; हालांकि मैं सीख
जाऊंगा

1
ठीक है, मुझे लगता है कि इस सवाल पर बहुत स्पष्ट है कि क्या किया जाना चाहिए, प्रत्येक फ़ाइल के बारे में निर्देशिका ट्री और आउटपुट जानकारी के माध्यम से जाना। सवाल बहुत स्पष्ट है, और पहले से ही जवाब की मात्रा से देखते हुए, लोग इसे काफी अच्छी तरह से समझते हैं। अस्पष्ट होने के लिए 3 वोट वास्तव में इस प्रश्न के योग्य नहीं हैं
सर्गिय कोलोडाज़नी

जवाबों:


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बाहर निकलने के लिए।

2. स्क्रिप्ट की सामग्री 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                    

3. स्पष्टीकरण:

  • walk()समारोह का मुख्य तंत्र उसके उत्तर में ज़ाना द्वारा बहुत अच्छी तरह से वर्णित है । इसलिए मैं केवल नए भाग का वर्णन करूंगा।

  • walk()फ़ंक्शन के भीतर मैंने यह लूप जोड़ा है:

    for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done

    इसका मतलब है $entryकि प्रत्येक फ़ाइल के लिए फ़ंक्शन निष्पादित किया जाएगा file_specification()

  • फ़ंक्शन file_specification()के दो भाग हैं। पहले भाग को फ़ाइल से संबंधित डेटा मिलता है - नाम, पथ, आकार आदि। दूसरा भाग डेटा को अच्छी तरह से स्वरूपित करता है। डेटा को प्रारूपित करने के लिए कमांड का उपयोग किया जाता है printf। और यदि आप स्क्रिप्ट को ट्विक करना चाहते हैं तो आपको इस कमांड के बारे में पढ़ना चाहिए - उदाहरण के लिए यह लेख

  • फ़ंक्शन file_specification()अच्छी जगह है जहां आप विशिष्ट कमांड रख सकते हैं जिसे प्रत्येक फ़ाइल के लिए निष्पादित किया जाना चाहिए । इस प्रारूप का उपयोग करें:

    कमांड "$ {प्रविष्टि}"

    या आप कमांड के आउटपुट को वेरिएबल के रूप में सेव कर सकते हैं, और फिर printfइस वेरिएबल आदि को।:

    MY_VAR = "$ ( कमांड " $ {प्रविष्टि} ")"
    प्रिंटफ "% * s \ tFile आकार: \ t $ {YEL}% s $ {NCL} \ n" $ ((इंडेंट + 4)) '' $ MY_VAR "

    या सीधे printfकमांड का आउटपुट:

    प्रिंटफ "% * s \ tFile आकार: \ t $ {YEL}% s $ {NCL} \ n" $ ((इंडेंट + 4)) '' "$ ( कमांड " $ {प्रविष्टि} ")"

  • भीख मांगने के लिए खंड, कहा जाता है Colourise the output, कुछ चर है कि printfउत्पादन को बढ़ावा देने के लिए आदेश के भीतर उपयोग कर रहे हैं । इसके बारे में अधिक जानकारी आपको यहाँ मिल सकती है

  • विभाजन के नीचे अतिरिक्त शर्त जोड़ी जाती है जो पूर्ण और सापेक्ष रास्तों से संबंधित है।

4. उपयोग के उदाहरण:

  • 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. उपयोग का प्रदर्शन:

यहां छवि विवरण दर्ज करें


यह बहुत काम है, लेकिन अच्छा दिखता है। बहुत बढ़िया !
सर्गी कोलोडियाज़नी

आप उन gifs @ pa4080 को बनाने के लिए किस प्रक्रिया का उपयोग कर रहे हैं?
pbhj

@pbhj, उबंटू के तहत मैं पीक का उपयोग कर रहा हूं यह सरल और अच्छा है, लेकिन कभी-कभी क्रैश हो जाता है और संपादन क्षमता नहीं होती है। मेरे अधिकांश GIF विंडोज के तहत बनाए गए हैं, जहां मैं VNC कनेक्शन की विंडो रिकॉर्ड कर रहा हूं। मेरे पास एक अलग डेस्कटॉप मशीन है जो मुख्य रूप से मैं एमएस ऑफिस और जीआईएफ निर्माण के लिए उपयोग कर रहा हूं :) जो टूल मैं वहां उपयोग कर रहा हूं वह स्क्रीनटॉफ है । यह ओपन सोर्स, फ्री और शक्तिशाली एडिटर और प्रोसेसिंग मैकेनिसम है। दुर्भाग्य से मैं Ubuntu के लिए ScreenToGif जैसे टूल नहीं खोज सकता।
2240 पर 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


यदि आप पूरा फ़ाइल नाम छाप रहे हैं, तो "एक्सटेंशन" आपको क्या देता है? शायद आप MIME जानकारी चाहते हैं कि "$(file "$i")"(उपरोक्त स्क्रिप्ट में एक प्रिंटफ के दूसरे भाग के रूप में) वापस आ जाएगी?
pbhj

1
@pbhj मुझे व्यक्तिगत रूप से? कुछ भी तो नहीं। लेकिन ओपी ने जो सवाल पूछा वह पूछा गया था output the path, filename, extension, filesize , इसलिए उत्तर वही है जो पूछा जाता है। :)
सर्गी कोलोडाज़हनी

12

आप findकाम करने के लिए उपयोग कर सकते हैं

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

यह आपकी मदद करेगा यदि आप केवल आकार वाली सभी फ़ाइलों को सूचीबद्ध करना चाहते हैं।

-execआपको \;फ़ाइलों को पार्स करने के लिए उपयोग की जाने वाली प्रत्येक फ़ाइल के लिए कस्टम कमांड या स्क्रिप्ट को निष्पादित करने की अनुमति देगा , +;यदि आप उन्हें संक्षिप्त करना चाहते हैं (तो फ़ाइल नाम का अर्थ है)।


यह अच्छा है, लेकिन ओपी द्वारा उल्लिखित सभी आवश्यकताओं का जवाब नहीं है।
α atsнιη

1
@ α asнιη मैंने बस उसे काम करने के लिए एक टेम्पलेट दिया। मुझे पता है, यह इस सवाल का पूरा जवाब नहीं है, क्योंकि मुझे लगता है कि यह सवाल खुद व्यापक है।
राजेश राजेंद्रन

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
डेविड फ़ॉस्टर

1

यदि आप जानते हैं कि पेड़ कितना गहरा है, तो वाइल्डकार्ड का उपयोग करने का सबसे आसान तरीका होगा *

शेल स्क्रिप्ट या फ़ंक्शन के रूप में आप जो कुछ भी करना चाहते हैं, उसे लिखें

function thing() { ... }

फिर चला for i in *; do thing "$i"; done, for i in */*; do thing "$i"; done... आदि

अपने फ़ंक्शन / स्क्रिप्ट के भीतर, आप उन फ़ाइलों को एकल करने के लिए कुछ सरल परीक्षणों का उपयोग कर सकते हैं, जिनके साथ आप काम करना चाहते हैं और जो कुछ भी आपको उनके साथ करना है।


"यह आपके किसी भी फ़ाइल नाम में रिक्त स्थान होने पर काम नहीं करेगा ..." क्योंकि आपका चर आपके चर का उद्धरण करना भूल गया है! के बजाय "$ i" का उपयोग करें $i
मूरू

@ नहीं, कारण यह काम नहीं करता है क्योंकि "रिक्त स्थान पर लूप विभाजन के लिए" - " / 'सभी फ़ाइलों की एक अंतरिक्ष-पृथक सूची में विस्तारित हो जाता है। आप इसके चारों ओर काम कर सकते हैं, जैसे IFS के साथ गड़बड़ करके। लेकिन उस बिंदु पर आप केवल खोज का उपयोग कर सकते हैं।
बेनुबर्ड

@ p4080 इस उत्तर के लिए प्रासंगिक नहीं है, लेकिन यह वैसे भी सुपर उपयोगी लगता है, धन्यवाद!
बेनुबर्ड

मुझे लगता है कि आपको समझ में नहीं आता कि कैसे 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"' {} \;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.