It is well described how to verify file existence or type, but there is much more information that can be easily verified inside shell script using nothing more than simple stat
command.
Table of contents
Size
I will start with the simplest thing to check, which is the file size.
#!/bin/sh # print file size # stat command stat_cmd=$(which stat) # file to be verified file=$1 if [ -f "$file" ]; then size=$($stat_cmd --format="%s" $file) # bytes units="B" if [ "$size" -gt "1024" ]; then size=$(expr $size / 1024) # kilobytes units="KB" fi if [ "$size" -gt "1024" ]; then size=$(expr $size / 1024) # megabytes units="MB" fi if [ "$size" -gt "1024" ]; then size=$(expr $size / 1024) # gigabytes units="GB" fi if [ "$size" -gt "1024" ]; then size=$(expr $size / 1024) # terabytes units="TB" fi echo "$file size is $size $units" else echo "File does not exist" fi
Type
The next thing that can be easily verified is the file type.
#!/bin/sh # print file type # stat command stat_cmd=$(which stat) # file to be verified file=$1 if [ -e "$file" ]; then type=$(LC_ALL=C $stat_cmd --format="%F" $file) echo -n "$file type is " case $type in "regular file"|"directory"|"symbolic link"|"fifo"|"character special file"|"block special file"|"socket") echo $type ;; *) echo "unknown" esac else echo "File does not exist" fi
The above shell script is very descriptive. The equivalent solution would be to use a human-readable form of permissions.
#!/bin/sh # alternative way to print file type # stat command stat_cmd=$(which stat) # file to be verified file=$1 if [ -e "$file" ]; then type=$($stat_cmd --format="%A" $file | cut -c 1) echo -n "$file type is " case $type in "-") echo "regular file";; "d") echo "directory";; "l") echo "symbolic link";; "p") echo "fifo";; "c") echo "character special file";; "b") echo "block special file";; "s") echo "socket";; *) echo "unknown" esac else echo "File does not exist" fi
Ownership
Owner
You can quickly verify the file owner using the following constructs.
#!/bin/sh # print and verify file owner # stat command stat_cmd=$(which stat) # file to be verified file=$1 if [ -e "$file" ]; then user_id="$($stat_cmd --format="%u" $file)" user_name="$($stat_cmd --format="%U" $file)" echo "$file owner is $user_name ($user_id)" # verify UID if [ "$user_id" -ge "1000" ]; then echo "This file belongs to regular user" else echo "This file belongs to system user" fi # verify user name if [ "$user_name" = "milosz" ]; then echo "This file belongs to milosz user" else echo "This file does not belong to milosz user" fi else echo "File does not exist" fi
Group
The filegroup can be verified in the same way as the above one.
#!/bin/sh # print and verify file group # stat command stat_cmd=$(which stat) # file to be verified file=$1 if [ -e "$file" ]; then group_id="$($stat_cmd --format="%g" $file)" group_name="$($stat_cmd --format="%G" $file)" echo "$file group is $group_name ($group_id)" # verify GID if [ "$group_id" -ge "1000" ]; then echo "This file belongs to regular group" else echo "This file belongs to system group" fi # verify group name if [ "$group_name" = "root" ]; then echo "This file belongs to root group" else echo "This file does not belong to root group" fi else echo "File does not exist" fi
Permissions
This one is more interesting as you can use octal or human-readable representation.
Verify permissions
The simplest way to verify permissions is to use octal representation.
#!/bin/sh # check file permissions # stat command stat_cmd=$(which stat) # file to be verified file=$1 if [ -e "$file" ]; then if [ "$($stat_cmd --format="%a" $file | xargs printf "%04d")" = "0755" ]; then echo "$file 0755 proper permission confirmed" fi else echo "File does not exist" fi
Analyze permissions using human-readable representation
You can simply translate human-readable representation [-rwxr-xr-x
].
#!/bin/sh # analyse file permissions # stat command stat_cmd=$(which stat) # file to be verified file=$1 if [ -e "$file" ]; then # parse "-rwxr-xr-x" format # skip first character (file type) rights=$($stat_cmd --format="%A" $file | cut -c 2-) # for class in $(seq 1 3); do # rwx r-x r-x case $class in # o g o 1) # w r t echo " * owner" # n o h ;; # e u e 2) # r p r echo " * group" # ;; 3) echo " * other" ;; esac # range to cut for each class from=$(expr 3 \* $class - 2) # (1) 1 (2) 4 (3) 7 to=$(expr 3 \* $class) # 3 6 9 # 1st step rwx, 2nd step r-x, 3rd step r-x class_perm=$(echo $rights | cut -c ${from}-${to}) for pos in $(seq 1 3); do mode=$(echo $class_perm | cut -c $pos) case $mode in "r") echo " read" ;; "w") echo " write" ;; "x") echo " execute" ;; "s") if [ "$class" = 1 ]; then echo " execute and SUID" else echo " execute and SGID" fi ;; "S") if [ "$class" = 1 ]; then echo " SUID" else echo " SGID" fi ;; "t") echo " execute and sticky bit" ;; "T") echo " sticky bit" ;; esac done done else echo "File does not exist" fi
Analyze permissions using octal representation
I prefer this way as this is a quite interesting solution – read octal representation, convert to binary, then translate.
#!/bin/sh # check file permissions # stat command stat_cmd=$(which stat) # file to be verified file=$1 if [ -e "$file" ]; then # parse "0755" format, convert "755" to "0755" rights=$($stat_cmd --format="%a" $file | xargs printf "%04d") for class in $(seq 0 3); do # case $class in # 0 7 5 5 0) # s o g o echo " * special" # p w r t ;; # e n o h 1) # c e u e echo " * owner" # i r p r ;; # a 2) # l echo " * group" # ;; 3) echo " * other" ;; esac class_pos=$(expr $class + 1) # class position 1..4 class_perm=$(echo $rights | cut -c $class_pos) # octal class rep perm_bin=$(echo "obase=2; $class_perm" | bc | xargs printf "%03d") # convert it to binary # 1st step 111 (7), 2nd step 101 (5), 3rd step 101 (5) # parse binary representation for pos in $(seq 1 3); do mode=$(echo $perm_bin | cut -c $pos) if [ "$class" = "0" ]; then # special if [ "$mode" = 1 -a "$pos" = "1" ]; then # [1]XX echo " SUID"; elif [ "$mode" = 1 -a "$pos" = "2" ]; then # X[1]X echo " SGID"; elif [ "$mode" = 1 -a "$pos" = "3" ]; then # XX[1] echo " sticky bit"; fi else # regular if [ "$mode" = 1 -a "$pos" = "1" ]; then # [1]XX echo " read"; elif [ "$mode" = 1 -a "$pos" = "2" ]; then # X[1]X echo " write"; elif [ "$mode" = 1 -a "$pos" = "3" ]; then # XX[1] echo " execute"; fi fi done done else echo "File does not exist" fi
Time of last access and modification
Print times
You can simply display times using the following code.
#!/bin/sh # print file last access and modification date # stat command stat_cmd=$(which stat) # file to be verified file=$1 if [ -f "$file" ]; then mod_time=$($stat_cmd --format="%y" $file) acc_time=$($stat_cmd --format="%x" $file) echo "$file last access is $acc_time, modification time is $mod_time" else echo "File does not exist" fi
Compare times
Again, the most interesting part is the date comparison using seconds since the Epoch.
#!/bin/sh # compare file last access and modification date with contrived date values # stat command stat_cmd=$(which stat) # file to be verified file=$1 if [ -e "$file" ]; then mod_time=$($stat_cmd --format="%Y" $file) acc_time=$($stat_cmd --format="%X" $file) if [ "$mod_time" -ge "$(date -d "00:00" +"%s")" ]; then echo "$file was modified today" fi if [ "$acc_time" -ge "$(date -d "last day" +"%s")" ]; then echo "$file was accessed at least yesterday" fi if [ "$mod_time" -ge "$(date -d "2014-11-09 19:00" +"%s")" -a "$mod_time" -le "$(date -d "2014-11-09 20:00" +"%s")" ]; then echo "$file was modified 2014-11-09 between 19:00 and 20:00" fi if [ "$acc_time" -lt "$(date -d "-3 days" +"%s")" ]; then echo "$file was accessed more then three days ago" fi else echo "File does not exist" fi
Ending notes
You can perform more interesting things using the techniques shown here. All I can do now is to suggest to check out stat
manual page and GNU coreutils manual.