?? directory-info.sh
字號:
#! /bin/bash# directory-info.sh# Parses and lists directory information.# NOTE: Change lines 273 and 353 per "README" file.# Michael Zick is the author of this script.# Used here with his permission.# Controls# If overridden by command arguments, they must be in the order:# Arg1: "Descriptor Directory"# Arg2: "Exclude Paths"# Arg3: "Exclude Directories"## Environment Settings override Defaults.# Command arguments override Environment Settings.# Default location for content addressed file descriptors.MD5UCFS=${1:-${MD5UCFS:-'/tmpfs/ucfs'}}# Directory paths never to list or enterdeclare -a \ EXCLUDE_PATHS=${2:-${EXCLUDE_PATHS:-'(/proc /dev /devfs /tmpfs)'}}# Directories never to list or enterdeclare -a \ EXCLUDE_DIRS=${3:-${EXCLUDE_DIRS:-'(ucfs lost+found tmp wtmp)'}}# Files never to list or enterdeclare -a \ EXCLUDE_FILES=${3:-${EXCLUDE_FILES:-'(core "Name with Spaces")'}}# Here document used as a comment block.: <<LSfieldsDoc# # # # # List Filesystem Directory Information # # # # ### ListDirectory "FileGlob" "Field-Array-Name"# or# ListDirectory -of "FileGlob" "Field-Array-Filename"# '-of' meaning 'output to filename'# # # # #String format description based on: ls (GNU fileutils) version 4.0.36Produces a line (or more) formatted:inode permissions hard-links owner group ...32736 -rw------- 1 mszick mszicksize day month date hh:mm:ss year path2756608 Sun Apr 20 08:53:06 2003 /home/mszick/coreUnless it is formatted:inode permissions hard-links owner group ...266705 crw-rw---- 1 root uucpmajor minor day month date hh:mm:ss year path4, 68 Sun Apr 20 09:27:33 2003 /dev/ttyS4NOTE: that pesky comma after the major numberNOTE: the 'path' may be multiple fields:/home/mszick/core/proc/982/fd/0 -> /dev/null/proc/982/fd/1 -> /home/mszick/.xsession-errors/proc/982/fd/13 -> /tmp/tmpfZVVOCs (deleted)/proc/982/fd/7 -> /tmp/kde-mszick/ksycoca/proc/982/fd/8 -> socket:[11586]/proc/982/fd/9 -> pipe:[11588]If that isn't enough to keep your parser guessing,either or both of the path components may be relative:../Built-Shared -> Built-Static../linux-2.4.20.tar.bz2 -> ../../../SRCS/linux-2.4.20.tar.bz2The first character of the 11 (10?) character permissions field:'s' Socket'd' Directory'b' Block device'c' Character device'l' Symbolic linkNOTE: Hard links not marked - test for identical inode numberson identical filesystems.All information about hard linked files are shared, exceptfor the names and the name's location in the directory system.NOTE: A "Hard link" is known as a "File Alias" on some systems.'-' An undistingushed fileFollowed by three groups of letters for: User, Group, OthersCharacter 1: '-' Not readable; 'r' ReadableCharacter 2: '-' Not writable; 'w' WritableCharacter 3, User and Group: Combined execute and special'-' Not Executable, Not Special'x' Executable, Not Special's' Executable, Special'S' Not Executable, SpecialCharacter 3, Others: Combined execute and sticky (tacky?)'-' Not Executable, Not Tacky'x' Executable, Not Tacky't' Executable, Tacky'T' Not Executable, TackyFollowed by an access indicatorHaven't tested this one, it may be the eleventh characteror it may generate another field' ' No alternate access'+' Alternate accessLSfieldsDocListDirectory(){ local -a T local -i of=0 # Default return in variable# OLD_IFS=$IFS # Using BASH default ' \t\n' case "$#" in 3) case "$1" in -of) of=1 ; shift ;; * ) return 1 ;; esac ;; 2) : ;; # Poor man's "continue" *) return 1 ;; esac # NOTE: the (ls) command is NOT quoted (") T=( $(ls --inode --ignore-backups --almost-all --directory \ --full-time --color=none --time=status --sort=none \ --format=long $1) ) case $of in # Assign T back to the array whose name was passed as $2 0) eval $2=\( \"\$\{T\[@\]\}\" \) ;; # Write T into filename passed as $2 1) echo "${T[@]}" > "$2" ;; esac return 0 }# # # # # Is that string a legal number? # # # # ### IsNumber "Var"# # # # # There has to be a better way, sigh...IsNumber(){ local -i int if [ $# -eq 0 ] then return 1 else (let int=$1) 2>/dev/null return $? # Exit status of the let thread fi}# # # # # Index Filesystem Directory Information # # # # ### IndexList "Field-Array-Name" "Index-Array-Name"# or# IndexList -if Field-Array-Filename Index-Array-Name# IndexList -of Field-Array-Name Index-Array-Filename# IndexList -if -of Field-Array-Filename Index-Array-Filename# # # # #: <<IndexListDocWalk an array of directory fields produced by ListDirectoryHaving suppressed the line breaks in an otherwise line orientedreport, build an index to the array element which starts each line.Each line gets two index entries, the first element of each line(inode) and the element that holds the pathname of the file.The first index entry pair (Line-Number==0) are informational:Index-Array-Name[0] : Number of "Lines" indexedIndex-Array-Name[1] : "Current Line" pointer into Index-Array-NameThe following index pairs (if any) hold element indexes intothe Field-Array-Name per:Index-Array-Name[Line-Number * 2] : The "inode" field element.NOTE: This distance may be either +11 or +12 elements.Index-Array-Name[(Line-Number * 2) + 1] : The "pathname" element.NOTE: This distance may be a variable number of elements.Next line index pair for Line-Number+1.IndexListDocIndexList(){ local -a LIST # Local of listname passed local -a -i INDEX=( 0 0 ) # Local of index to return local -i Lidx Lcnt local -i if=0 of=0 # Default to variable names case "$#" in # Simplistic option testing 0) return 1 ;; 1) return 1 ;; 2) : ;; # Poor man's continue 3) case "$1" in -if) if=1 ;; -of) of=1 ;; * ) return 1 ;; esac ; shift ;; 4) if=1 ; of=1 ; shift ; shift ;; *) return 1 esac # Make local copy of list case "$if" in 0) eval LIST=\( \"\$\{$1\[@\]\}\" \) ;; 1) LIST=( $(cat $1) ) ;; esac # Grok (grope?) the array Lcnt=${#LIST[@]} Lidx=0 until (( Lidx >= Lcnt )) do if IsNumber ${LIST[$Lidx]} then local -i inode name local ft inode=Lidx local m=${LIST[$Lidx+2]} # Hard Links field ft=${LIST[$Lidx+1]:0:1} # Fast-Stat case $ft in b) ((Lidx+=12)) ;; # Block device c) ((Lidx+=12)) ;; # Character device *) ((Lidx+=11)) ;; # Anything else esac name=Lidx case $ft in -) ((Lidx+=1)) ;; # The easy one b) ((Lidx+=1)) ;; # Block device c) ((Lidx+=1)) ;; # Character device d) ((Lidx+=1)) ;; # The other easy one l) ((Lidx+=3)) ;; # At LEAST two more fields# A little more elegance here would handle pipes,#+ sockets, deleted files - later. *) until IsNumber ${LIST[$Lidx]} || ((Lidx >= Lcnt)) do ((Lidx+=1)) done ;; # Not required esac INDEX[${#INDEX[*]}]=$inode INDEX[${#INDEX[*]}]=$name INDEX[0]=${INDEX[0]}+1 # One more "line" found# echo "Line: ${INDEX[0]} Type: $ft Links: $m Inode: \# ${LIST[$inode]} Name: ${LIST[$name]}" else ((Lidx+=1)) fi done case "$of" in 0) eval $2=\( \"\$\{INDEX\[@\]\}\" \) ;; 1) echo "${INDEX[@]}" > "$2" ;; esac return 0 # What could go wrong?}# # # # # Content Identify File # # # # ### DigestFile Input-Array-Name Digest-Array-Name# or# DigestFile -if Input-FileName Digest-Array-Name# # # # ## Here document used as a comment block.: <<DigestFilesDocThe key (no pun intended) to a Unified Content File System (UCFS)is to distinguish the files in the system based on their content.Distinguishing files by their name is just, so, 20th Century.The content is distinguished by computing a checksum of that content.This version uses the md5sum program to generate a 128 bit checksumrepresentative of the file's contents.There is a chance that two files having different content mightgenerate the same checksum using md5sum (or any checksum). Shouldthat become a problem, then the use of md5sum can be replace by acyrptographic signature. But until then...The md5sum program is documented as outputting three fields (and itdoes), but when read it appears as two fields (array elements). Thisis caused by the lack of whitespace between the second and third field.So this function gropes the md5sum output and returns: [0] 32 character checksum in hexidecimal (UCFS filename) [1] Single character: ' ' text file, '*' binary file [2] Filesystem (20th Century Style) name Note: That name may be the character '-' indicating STDIN read.DigestFilesDocDigestFile(){ local if=0 # Default, variable name local -a T1 T2 case "$#" in 3) case "$1" in -if) if=1 ; shift ;; * ) return 1 ;; esac ;; 2) : ;; # Poor man's "continue" *) return 1 ;; esac case $if in 0) eval T1=\( \"\$\{$1\[@\]\}\" \) T2=( $(echo ${T1[@]} | md5sum -) ) ;; 1) T2=( $(md5sum $1) ) ;; esac case ${#T2[@]} in 0) return 1 ;; 1) return 1 ;; 2) case ${T2[1]:0:1} in # SanScrit-2.0.5 \*) T2[${#T2[@]}]=${T2[1]:1} T2[1]=\* ;; *) T2[${#T2[@]}]=${T2[1]} T2[1]=" " ;; esac ;; 3) : ;; # Assume it worked *) return 1 ;; esac local -i len=${#T2[0]} if [ $len -ne 32 ] ; then return 1 ; fi eval $2=\( \"\$\{T2\[@\]\}\" \)}# # # # # Locate File # # # # ### LocateFile [-l] FileName Location-Array-Name# or# LocateFile [-l] -of FileName Location-Array-FileName# # # # ## A file location is Filesystem-id and inode-number# Here document used as a comment block.: <<StatFieldsDoc Based on stat, version 2.2 stat -t and stat -lt fields [0] name [1] Total size File - number of bytes Symbolic link - string length of pathname [2] Number of (512 byte) blocks allocated [3] File type and Access rights (hex) [4] User ID of owner [5] Group ID of owner [6] Device number [7] Inode number [8] Number of hard links [9] Device type (if inode device) Major [10] Device type (if inode device) Minor [11] Time of last access May be disabled in 'mount' with noatime atime of files changed by exec, read, pipe, utime, mknod (mmap?) atime of directories changed by addition/deletion of files [12] Time of last modification mtime of files changed by write, truncate, utime, mknod mtime of directories changed by addtition/deletion of files [13] Time of last change ctime reflects time of changed inode information (owner, group permissions, link count-*-*- Per: Return code: 0 Size of array: 14 Contents of array Element 0: /home/mszick Element 1: 4096 Element 2: 8 Element 3: 41e8 Element 4: 500 Element 5: 500 Element 6: 303 Element 7: 32385 Element 8: 22 Element 9: 0 Element 10: 0 Element 11: 1051221030 Element 12: 1051214068 Element 13: 1051214068 For a link in the form of linkname -> realname stat -t linkname returns the linkname (link) information stat -lt linkname returns the realname information stat -tf and stat -ltf fields [0] name [1] ID-0? # Maybe someday, but Linux stat structure [2] ID-0? # does not have either LABEL nor UUID # fields, currently information must come # from file-system specific utilities These will be munged into: [1] UUID if possible [2] Volume Label if possible Note: 'mount -l' does return the label and could return the UUID [3] Maximum length of filenames [4] Filesystem type [5] Total blocks in the filesystem [6] Free blocks [7] Free blocks for non-root user(s) [8] Block size of the filesystem [9] Total inodes [10] Free inodes-*-*- Per: Return code: 0 Size of array: 11 Contents of array Element 0: /home/mszick Element 1: 0 Element 2: 0 Element 3: 255 Element 4: ef53 Element 5: 2581445 Element 6: 2277180 Element 7: 2146050 Element 8: 4096 Element 9: 1311552 Element 10: 1276425StatFieldsDoc# LocateFile [-l] FileName Location-Array-Name# LocateFile [-l] -of FileName Location-Array-FileNameLocateFile(){ local -a LOC LOC1 LOC2 local lk="" of=0 case "$#" in 0) return 1 ;; 1) return 1 ;; 2) : ;; *) while (( "$#" > 2 )) do case "$1" in -l) lk=-1 ;; -of) of=1 ;; *) return 1 ;; esac shift done ;; esac# More Sanscrit-2.0.5 # LOC1=( $(stat -t $lk $1) ) # LOC2=( $(stat -tf $lk $1) ) # Uncomment above two lines if system has "stat" command installed. LOC=( ${LOC1[@]:0:1} ${LOC1[@]:3:11} ${LOC2[@]:1:2} ${LOC2[@]:4:1} ) case "$of" in 0) eval $2=\( \"\$\{LOC\[@\]\}\" \) ;; 1) echo "${LOC[@]}" > "$2" ;; esac return 0# Which yields (if you are lucky, and have "stat" installed)# -*-*- Location Discriptor -*-*-# Return code: 0# Size of array: 15# Contents of array# Element 0: /home/mszick 20th Century name# Element 1: 41e8 Type and Permissions# Element 2: 500 User# Element 3: 500 Group# Element 4: 303 Device# Element 5: 32385 inode# Element 6: 22 Link count# Element 7: 0 Device Major# Element 8: 0 Device Minor# Element 9: 1051224608 Last Access# Element 10: 1051214068 Last Modify# Element 11: 1051214068 Last Status# Element 12: 0 UUID (to be)# Element 13: 0 Volume Label (to be)# Element 14: ef53 Filesystem type}# And then there was some test codeListArray() # ListArray Name{ local -a Ta eval Ta=\( \"\$\{$1\[@\]\}\" \) echo echo "-*-*- List of Array -*-*-" echo "Size of array $1: ${#Ta[*]}" echo "Contents of array $1:" for (( i=0 ; i<${#Ta[*]} ; i++ )) do echo -e "\tElement $i: ${Ta[$i]}" done return 0}declare -a CUR_DIR# For small arraysListDirectory "${PWD}" CUR_DIRListArray CUR_DIRdeclare -a DIR_DIGDigestFile CUR_DIR DIR_DIGecho "The new \"name\" (checksum) for ${CUR_DIR[9]} is ${DIR_DIG[0]}"declare -a DIR_ENT# BIG_DIR # For really big arrays - use a temporary file in ramdisk# BIG-DIR # ListDirectory -of "${CUR_DIR[11]}/*" "/tmpfs/junk2"ListDirectory "${CUR_DIR[11]}/*" DIR_ENTdeclare -a DIR_IDX# BIG-DIR # IndexList -if "/tmpfs/junk2" DIR_IDXIndexList DIR_ENT DIR_IDXdeclare -a IDX_DIG# BIG-DIR # DIR_ENT=( $(cat /tmpfs/junk2) )# BIG-DIR # DigestFile -if /tmpfs/junk2 IDX_DIGDigestFile DIR_ENT IDX_DIG# Small (should) be able to parallize IndexList & DigestFile# Large (should) be able to parallize IndexList & DigestFile & the assignmentecho "The \"name\" (checksum) for the contents of ${PWD} is ${IDX_DIG[0]}"declare -a FILE_LOCLocateFile ${PWD} FILE_LOCListArray FILE_LOCexit 0
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -