1

I am trying to build a condition that check if file has execute access bit set. I can't use grep and find.

I tried something with checking the "x" letter in the ls -l command but this is wrong in many cases.

for val in `ls $1`
do
  if [[ "`ls -l $1/$val`" -eq *w* ]]
  then
    rm $1/$val
  fi
done

Please help or give some advices!

codeforester
  • 39,467
  • 16
  • 112
  • 140
demoo
  • 111
  • 2
  • 3
  • 11

2 Answers2

6

There is no need to parse the output of ls to see if a file is executable. Shell provides the built-in -x check for that. Using -x feature, your loop could be re-written as:

for file in "$1"/*; do
  [[ -x "$file" ]] && rm -- "$file"
done

See also:

codeforester
  • 39,467
  • 16
  • 112
  • 140
  • 1
    `"$1"/*`, you mean (to handle spaces in the directory name). And `rm -- "$file"`, if we want to handle the case where `$1` is a directory name that starts with a dash. – Charles Duffy Mar 06 '17 at 19:02
1
if [ -x "$file" ]; then
  # do something
fi

You can get many more options of file testing using man :

~]# man test
.... 
-x FILE
              FILE exists and execute (or search) permission is granted

Following should work:

 ~]# find $1 -type f | while IFS='' read -r -d '' p; 
     do 
        if [ -x "$p" ]; then 
           echo "removing $p";
           rm "$p";
        fi; 
     done

find command gets all the files (including .) in the directory given by $1. while reads each of these output, if then checks individual files for executable permission with-x.

EDIT

After some comments, here is a swifter example:

find "$1" -type f -executable -exec rm -- {} \;
iamauser
  • 11,119
  • 5
  • 34
  • 52
  • 1
    `[ -x $file ]` will falsely return true if `$file` is an empty string, because it will run `[ -x ]`, which tests if `-x` is an empty string (and, since it's non-empty, returns true). Use quotes: `[ -x "$file" ]` – Charles Duffy Mar 06 '17 at 19:01
  • 1
    This also isn't at all covering correctly/robustly retrieving filenames (```for val in `ls $1` ``` is full of known issues: won't handle names with spaces correctly, behavior with nonprintable characters varies between platforms, behavior with filenames containing newline literals is *entirely* undefined, etc). – Charles Duffy Mar 06 '17 at 19:08
  • 2
    Parsing the output of `find` fails in every instance where parsing the output of `ls` would, and it isn't even necessary. You can use the `-perm` primary to select the executable files, then use `-exec rm -- {} \;` (or `-delete`, if supported) to remove them. – chepner Mar 06 '17 at 19:56
  • Quotes! `find "$1" -type f -executable -exec rm -- {} +` -- without the quotes around `$1`' a directory named `./My Directory` would be passed as two arguments, `./My` and `Directory`. – Charles Duffy Mar 06 '17 at 20:27
  • Also, `-exec rm -- {} \;` is inefficient, running `rm` once per file found, whereas `-exec rm -- {} +` invokes `rm` as few times as possible, putting multiple filenames onto the command line for each invocation. – Charles Duffy Mar 06 '17 at 20:28
  • If you *do* want to pipe from `find`, by the way, make it: `find "$1" -type f -print0 | while IFS='' read -r -d '' p; do` -- that way you correctly handle names with literal backslashes, names with trailing whitespace, and names with literal newlines, none of which the current `find ... | while read` can deal with. See also the "Actions In Bulk" section of [UsingFind](http://mywiki.wooledge.org/UsingFind). – Charles Duffy Mar 06 '17 at 20:29