4

I have a folder containing many C source file and the same number of its compiled output files.

I set executable bit to all this files but for some reason it was lost, making them not executable. (I think that's because I moved that folder to a NTFS partition for a while).

I would like to make them (but not the other files in my directory) executable again. One possible way is to move all source file from that folder to a temporary folder and do:

chmod +x *

Then move source files back to current folder.

Is it possible to do the same without moving files around?

Note:

Compiled output files are extension-less (in C).

2
  • So you want to add executable bit to all files in current directory that do not have any extension in their name, right (so no dot in filename)? Oct 4, 2012 at 12:20
  • @KrzysztofAdamski Yes Oct 4, 2012 at 15:39

4 Answers 4

12

That depends on how you define which files should be set as executables. For example, if consider all the files that do not have dot in filename, you can use:

find -type f -not -name "*.*" -exec chmod +x \{\} \;

This will find recursively all the files (not directories) that do not have dot in file name and set them executable. If you want to limit this to only current directory, add -maxdepth 1 argument, like this:

find -maxdepth 1 -type f -not -name "*.*" -exec chmod +x \{\} \;

You could also rely on file command which could tell you if a file is ELF executable. To do this, you could run something like:

find -type f -exec /bin/sh -c "file {} | grep -q executable && chmod +x {}" \;

This will recursively find all regular files and call file command on them. Then, grep will look for "executable" string in the output of this command (it should be something like ELF 32-bit LSB executable ...) and only if it finds it, chmod will be called on this file.

Of course, you can also add -maxdepth 1 in this case to disable recursive searching.

4

You could do something like:

find /pathtostuff -type f ! -name "*.c" -exec chmod +x {} +

This looks in /pathtostuff for files that lack a .c extension and adds the execute permissions to them.

UPDATE

This can be expanded to handle other C extensions too:

find . -type f ! -name "*.c" ! -name "*.h" ! -name "*.cc" ! -name "*.cpp" -exec chmod +x {} +

ALTERNATIVE APPROACH

This script is extension agnostic. It looks for files that are "binary" as opposed to "text".

#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
my @dir = @ARGV ? @ARGV : ('.');
my @files;
find( sub { -f $_ && !-T $_ && push @files, $File::Find::name }, @dir );
for my $file (@files) {
    system("echo  +x $file");
}

Simply pass the directory path to be examined. Run the script without any argument to process the current working directory.

12
  • I'm surprised! It didn't asked for password. Oct 4, 2012 at 15:42
  • What if I want to exclude another extension? Say .cc. Oct 4, 2012 at 15:42
  • 1
    This is not really ideal since there may be .o/.h/.cpp and other files. Oct 4, 2012 at 15:45
  • 1
    @SantoshKumar: it don't need password for anything. Password is only needed when you use sudo command which is used to gain root privileges. As long as you run chmod on the files owned by the user you are logged in as, you don't have to use sudo. Oct 4, 2012 at 16:10
  • 1
    @JRFerguson: I don't want to be annoying with my comments but there may be some binary files that are not executable in the directory. For example .o files. Also consider how perl determines if file is binary or text file - it reads a block of file and check how many "odd" characters (controlcodes, metacharacters) are there. If it's more than 10% of such characters or if there is at least one null character in this block, it's considered binary file. This may produce some wrong results. In general, there is no good way to tell if it's binary or text file. Oct 4, 2012 at 19:45
3

In zsh:

setopt extendedglob
chmod +x -- ^*.c

With ksh, or bash with extglob option, or zsh with kshglob option:

chmod +x -- !(*.c)

With ksh93 (probably best to avoid playing with FIGNORE though):

FIGNORE='@(.*|*.c)'
chmod +x -- *

For all, replace *.c with *.* to exclude anything that has a dot.

With zsh, you can do nice things with globbing qualifiers, like:

oftype() [[ $(file -b --mime-type -- $REPLY) = $type ]]
type=application/x-executable; chmod +x -- **/*(.+oftype)

Which would match on regular files "oftype" application/x-executable (recursively descending into subdirectories).

1

This would also likely work

chmod +x $(find . -type f -print0 | xargs -0 file | grep "ELF [^,;]* executable" |  cut -d: -f1)

You'll still have problems if your files have spaces, tabs, newlines, asterisks, question marks, angle bracket or backslash characters in the names, or if there are too many of them to fit in one command line.

1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .