디렉토리 구조에서 각 파일에 대한 정보를 수집하는 재귀 bash 스크립트


14

디렉토리 트리를 통해 재귀 적으로 작업하고 각 파일에서 특정 명령을 실행하고 경로, 파일 이름, 확장명, 파일 크기 및 기타 특정 텍스트를 bash의 단일 파일로 출력하는 방법은 무엇입니까?


롤, 편집 주셔서 감사합니다; 나는 hooman 세계에서 800 개의 관련없는 질문을받는 데 익숙하기 때문에 내가 너무 복잡한 것들을 인정한 첫 번째 사람이 될 것이다. 그래서 나는 질문에서 명백한 것에 대답하려고 노력합니다. 나는 비록 배울 것이다 :-)
SPooKYiNeSS

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()기능 의 주요 메커니즘은 Zanna의 대답 에 꽤 잘 설명되어 있습니다. 새로운 부분 만 설명하겠습니다.

  • walk()함수 내 에서이 루프를 추가했습니다.

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

    $entry, 파일 인 각각에 대해 함수가 실행됩니다 file_specification().

  • 이 기능 file_specification()에는 두 부분이 있습니다. 첫 번째 부분은 파일과 관련된 데이터 (이름, 경로, 크기 등)를 가져옵니다. 두 번째 부분은 올바른 형식의 데이터를 출력합니다. 데이터를 형식화하려면 명령이 사용됩니다 printf. 스크립트를 수정하려면 이 기사 와 같은 명령에 대해 읽어야 합니다.

  • 이 기능 file_specification()각 파일에 대해 실행해야하는 특정 명령을 넣을 수있는 좋은 위치 입니다. 이 형식을 사용하십시오.

    "$ {entry}" 명령

    또는 명령의 출력을 변수로 저장 한 다음 printf이 변수 등을 저장할 수 있습니다 .

    MY_VAR = "$ ( 명령 "$ {entry} ")"
    printf "% * s \ t 파일 크기 : \ t $ {YEL} % s $ {NCL} \ n"$ ((indent + 4)) '' "$ MY_VAR"

    또는 직접 printf명령의 출력 :

    printf "% * s \ t 파일 크기 : \ t $ {YEL} % s $ {NCL} \ n"$ ((indent + 4)) '' "$ ( command "$ {entry} ")"

  • 구걸 섹션 Colourise the outputprintf명령 내 에서 출력을 채색하기 위해 사용되는 몇 가지 변수를 초기화 합니다. 이에 대한 자세한 내용은 여기를 참조하십시오 .

  • 스크립의 맨 아래에는 절대 및 상대 경로를 처리하는 추가 조건이 추가됩니다.

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
  • 색상 코드없이 출력 파일을 만들려면 ( source ) :

    walk | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" > output.file

5. 사용 데모 :

여기에 이미지 설명을 입력하십시오


그것은 많은 작업이지만 잘 보입니다. 잘 했어 !
Sergiy Kolodyazhnyy

어떤 GIF를 @ pa4080으로 만들기 위해 어떤 프로세스를 사용하고 있습니까?
pbhj

@pbhj, Ubuntu에서 Peek를 사용 하는 것은 간단하고 훌륭하지만 때로는 충돌하고 편집 기능이 없습니다. 대부분의 GIF는 Windows에서 만들어지며 VNC 연결 창을 기록합니다. 주로 MS Office 및 GIF 제작에 사용하는 별도의 데스크톱 컴퓨터가 있습니다.) 내가 사용하는 도구는 ScreenToGif 입니다. 오픈 소스이며 무료이며 강력한 편집기 및 처리 메커니즘이 있습니다. 불행히도 Ubuntu 용 ScreenToGif와 같은 도구를 찾을 수 없습니다.
pa4080

13

아직 아무도 게시하지 않은 이유에 대해 약간 당황했지만 옵션을 사용하고 사용 bash하면 실제로 재귀 기능이 globstar있습니다.** glob . 따라서 다음과 같이 bash 재귀 globstar를 사용하는 (거의) 순수한 스크립트를 작성할 수 있습니다 .

#!/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.


전체 파일 이름을 인쇄하는 경우 "extension"은 어떤 추가 기능을 제공합니까? 아마도 "$(file "$i")"(위의 스크립트에서 printf의 두 번째 부분으로) 반환 되는 MIME 정보를 정말로 원 하십니까?
pbhj

1
@pbhj 개인적으로 나에게? 아무것도. 그러나 질문을 한 OP는에 대해 요청 output the path, filename, extension, filesize 했으므로 답변은 요청 된 내용과 일치합니다. :)
Sergiy Kolodyazhnyy

12

당신은 find일을 할 수 있습니다

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

크기가있는 모든 파일을 나열하려는 경우 도움이됩니다.

-exec\;파일을 하나씩 구문 분석하는 데 사용되는 각 파일에 대해 사용자 정의 명령 또는 스크립트를 실행할 수 있습니다 +;. 파일을 연결하려는 경우 사용할 수 있습니다 (파일 이름을 의미 함).


이는 훌륭하지만 언급 된 모든 요구 사항에 대한 답변은 아닙니다.
αғsнιη

1
@ αғsнιη 나는 그에게 작업 할 템플릿을 주었다. 나는 이것이 질문 자체의 범위가 넓다고 생각하기 때문에이 질문에 대한 완전한 대답은 아닙니다.
Rajesh Rajendran

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
David Foerster

1

트리의 깊이를 알고 있다면 가장 쉬운 방법은 와일드 카드를 사용하는 것 *입니다.

쉘 스크립트 나 함수로하고 싶은 모든 것을 작성하십시오

function thing() { ... }

그런 다음 , ... 등 을 실행하십시오 for i in *; do thing "$i"; done.for i in */*; do thing "$i"; done

함수 / 스크립트 내에서 간단한 테스트 를 사용 하여 작업하려는 파일을 찾아 내고 필요한 작업을 수행 할 수 있습니다.


"파일 이름에 공백이 있으면 작동하지 않습니다"... 변수를 인용하는 것을 잊었 기 때문에! 대신 "$ i"를 사용하십시오 $i.
muru

@muru 아니오, 작동하지 않는 이유는 "for"루프가 공백으로 분할되기 때문입니다. " / '는 공백으로 구분 된 모든 파일 목록으로 확장됩니다. 그러나 그 시점에서 당신은 단지 find를 사용할 것입니다
Benubird

@ pa4080이 답변과 관련이 없지만 어쨌든 매우 유용합니다. 감사합니다!
Benubird

나는 당신이 어떻게 for i in */*작동 하는지 이해하지 못한다고 생각 합니다. for i in */*; do printf "|%s|\n" "$i"; done
muru

인용 부호의 중요성에 대한 증거는 다음과 같습니다. 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.