BASH - counting the number of executable files - linux

Im trying to find the executables files and their total in a folder,its showing but the total is not this is my code below,can someone help me out were i am making mistakes,i am just a newbie trying to learn some bash scripting hope this is the right way of doing it thanks
#!/bin/bash
To="home/magie/d2"
cd "$To"
find . -type f -perm 755
if
find . -type f -perm 755
then
echo | echo wc -l
fi

If you want to find all the executable files then use this command:
find home/magie/d2 -type f -perm -u+rx | wc -l
OR
find home/magie/d2 -type f -perm +111 | wc -l
All the answers here are finding files with permission 755 only however keep in mind even 744 or 700 are also executable files by the user.

Just remove the if structure and the echo's
#!/bin/bash
To="home/magie/d2"
cd "$To"
find . -type f -perm 755
find . -type f -perm 755 | wc -l

Use /111 to find any file that has any of the execute bits set.
find . -type f -perm /111 | wc -l

I think I'd do something like this:
#!/bin/bash
dir=$1
files="$(find $dir -perm 755)"
total=$(wc -l <<< "$files")
echo "$files"
echo "Total: $total"
where the desired directory has to be passed as an argument in the command line and the quotes are used to preserve line breaks needed later by wc to correctly count the number of lines.

From the command line a simple one-liner should do the trick -
wc -l < <(find /home/magie/d2 -type f -perm 755)
<(..) is process substitution.

Related

Circumvent Argument list too long in script (for loop)

I've seen a few answers regarding this, but as a newbie, I don't really understand how to implement that in my script.
it should be pretty easy (for those who can stuff like this)
I'm using a simple
for f in "/drive1/"images*.{jpg,png}; do
but this is simply overloading and giving me
Argument list too long
How is this easiest solved?
Argument list too long workaroud
Argument list length is something limited by your config.
getconf ARG_MAX
2097152
But after discuss around differences between bash specifics and system (os) limitations (see comments from that other guy), this question seem wrong:
Regarding discuss on comments, OP tried something like:
ls "/simple path"/image*.{jpg,png} | wc -l
bash: /bin/ls: Argument list too long
This happen because of OS limitation, not bash!!
But tested with OP code, this work finely
for file in ./"simple path"/image*.{jpg,png} ;do echo -n a;done | wc -c
70980
Like:
printf "%c" ./"simple path"/image*.{jpg,png} | wc -c
Reduce line length by reducing fixed part:
First step: you could reduce argument length by:
cd "/drive1/"
ls images*.{jpg,png} | wc -l
But when number of file will grow, you'll be buggy again...
More general workaround:
find "/drive1/" -type f \( -name '*.jpg' -o -name '*.png' \) -exec myscript {} +
If you want this to NOT be recursive, you may add -maxdepth as 1st option:
find "/drive1/" -maxdepth 1 -type f \( -name '*.jpg' -o -name '*.png' \) \
-exec myscript {} +
There, myscript will by run with filenames as arguments. The command line for myscript is built up until it reaches a system-defined limit.
myscript /drive1/file1.jpg '/drive1/File Name2.png' /drive1/...
From man find:
-exec command {} +
This variant of the -exec action runs the specified command on
the selected files, but the command line is built by appending
each selected file name at the end; the total number of invoca‐
tions of the command will be much less than the number of
matched files. The command line is built in much the same way
that xargs builds its command lines. Only one instance of `{}'
Inscript sample
You could create your script like
#!/bin/bash
target=( "/drive1" "/Drive 2/Pictures" )
[ "$1" = "--run" ] && exec find "${target[#]}" -type f \( -name '*.jpg' -o \
-name '*.png' \) -exec $0 {} +
for file ;do
echo Process "$file"
done
Then you have to run this with --run as argument.
work with any number of files! (Recursively! See maxdepth option)
permit many target
permit spaces and special characters in file and directrories names
you could run same script directly on files, without --run:
./myscript hello world 'hello world'
Process hello
Process world
Process hello world
Using pure bash
Using arrays, you could do things like:
allfiles=( "/drive 1"/images*.{jpg,png} )
[ -f "$allfiles" ] || { echo No file found.; exit ;}
echo Number of files: ${#allfiles[#]}
for file in "${allfiles[#]}";do
echo Process "$file"
done
There's also a while read loop:
find "/drive1/" -maxdepth 1 -mindepth 1 -type f \( -name '*.jpg' -o -name '*.png' \) |
while IFS= read -r file; do
or with zero terminated files:
find "/drive1/" -maxdepth 1 -mindepth 1 -type f \( -name '*.jpg' -o -name '*.png' \) -print0 |
while IFS= read -r -d '' file; do

Bash - listing programs in all subdirectories with directory name before file

I don't need to do this in one line, but I've only got 1 line so far.
find . -perm -111 +type f | sort -r
What I'm trying to do is write a bash script that will display the list of all files in the current directory that are executable (z to a). I want the script to do the same for all subdirectories. What I'm having difficulty doing is displaying the name of the subdirectory before the list of executable files in that directory / subdirectory.
So, to clarify, desirable output might look like this:
program1
program2
SubDir1
program3
SubDirSubDir2
program4
SubDir2
program5
What I have right now (the above code) does this. Its not removing /path and it isn't listing the name of the new directory when directories are changed.
./exfile
./test/exfile1
./test1/program2
./test1/program
./first
Hopefully that was clear.
This will work.
I changed the permission to -100 because maybe some programs are only executable by its owner.
for d in $(find . -type d); do
echo "in $d:"
find $d -maxdepth 1 -perm -100 -type f | sed 's#.*/##'
done
This will do the trick for you.
find . -type d | sort | xargs -n1 -I{} bash -c "find {} -type f -maxdepth 1 -executable | sort -r"
The first find command lists all directories and sub directories and sort them in ascending order.
The sorted directories/sub-directories are then passed to xargs which calls bash to find the files within the directory/sub-directory and sort them in descending order.
If you prefer to also print the directory, you may run it without -type f.
You can use find on all directories and combine it with -print (to print the directory name) and -exec (to execute a find for files in that directory):
find . -type d -print -exec bash -c 'find {} -type f -depth 1 -perm +0111 | sort -r' \;
Let's break this down. First, you have the directory search:
find . -type d -print
Then the command to execute for each directory:
find {} -type f -depth 1 -perm +0111 | sort -r
The -exec switch will expand the path wherever it sees {}. Because this uses a pipe operator that is shell syntax, the whole thing is wrapped in bash -c.
You can expand on this further. If you want to strip the directory name off the files and space our your results nicer, something like this might suffice:
find {} -type f -depth 1 -print0 -perm +0111 | xargs -n1 -0 basename | sort -r && echo
Hmm, the sorting requirement makes this tricky - the "for d in $(find...)" command is clever, but hard to control the sorting. How about this? Everything is z->a, including the directories, but the awk statement is a bit of a monster ;_)
find `pwd` -perm 111 -type f |
sort -r |
xargs -n1 -I{} sh -c "dirname {};basename {}" |
awk '/^\// {dir=$0 ; if (dir != lastdir) {print;lastdir=dir}} !/^\// {print}'
Produces
/home/imcgowan/t/t3
jjj
iii
hhh
/home/imcgowan/t/t2
ggg
fff
eee
/home/imcgowan/t/t1
ddd
ccc
bbb
/home/imcgowan/t
aaa

Find and rename a directory

I am trying to find and rename a directory on a linux system.
the folder name is something like : thefoldername-23423-431321
thefoldername is consistent but the numbers change every time.
I tried this:
find . -type d -name 'thefoldername*' -exec mv {} newfoldername \;
The command actually works and rename that directory. But I got an error on terminal saying that there is no such file or directory.
How can I fix it?
It's a harmless error which you can get rid of with the -depth option.
find . -depth -type d -name 'thefoldername*' -exec mv {} newfoldername \;
Find's normal behavior is to process directories and then recurse into them. Since you've renamed it find complains when it tries to recurse. The -depth option tells find to recurse first, then process the directory after.
It's missing the -execdir option! As stated in man pages of find:
-execdir command {};
Like -exec, but the specified command is run from the subdirectory containing the matched file, which is not normally the directory in which you started find.
find . -depth -type d -name 'thefoldername*' -execdir mv {} newfoldername \;
With the previous answer my folders contents are disappeared.
This is my solution. It works well:
for i in find -type d -name 'oldFolderName';
do
dirname=$(dirname "$i")
mv $dirname/oldFolderName $dirname/newFolderName
done
.../ABC -> .../BCD
find . -depth -type d -name 'ABC' -execdir mv {} $(dirname $i)/BCD \;
Replace 1100 with old_value and 2200 with new_value that you want to replace.
example
for i in $(find . -type d -iname '1100');do echo "mv "$i" "$i"__" >> test.txt; sed 's/1100__/2200/g' test.txt > test_1.txt; bash test_1.txt ; rm test*.txt ; done
Proof
[user#server test]$ ls -la check/
drwxr-xr-x. 1 user user 0 Jun 7 12:16 1100
[user#server test]$ for i in $(find . -type d -iname '1100');do echo "mv "$i" "$i"__" >> test.txt; sed 's/1100__/2200/g' test.txt > test_1.txt; bash test_1.txt ; rm test*.txt ; done
[user#server test]$ ls -la check/
drwxr-xr-x. 1 user user 0 Jun 7 12:16 2200
here __ in sed is used only to change the name it have no other significance

Find executable files having no extensions?

Following program list me all files in a directory but how can I display only those 'executable' files having no extension ?
find $workingDir/testcases -type f -perm -og+rx | while read file
do
echo $file
done
You could use:
find $workingDir/testcases -type f ! -name "*.*" -perm -og+rx
#!/bin/bash
DIR="./";
find $DIR -type f -perm -og+rx | while read file
do
echo $file | egrep -v "\.[^/]+$";
done

How do I find all the files that were created today in Unix/Linux?

How do I find all the files that were create only today and not in 24 hour period in unix/linux
On my Fedora 10 system, with findutils-4.4.0-1.fc10.i386:
find <path> -daystart -ctime 0 -print
The -daystart flag tells it to calculate from the start of today instead of from 24 hours ago.
Note however that this will actually list files created or modified in the last day. find has no options that look at the true creation date of the file.
find . -mtime -1 -type f -print
To find all files that are modified today only (since start of day only, i.e. 12 am), in current directory and its sub-directories:
touch -t `date +%m%d0000` /tmp/$$
find . -type f -newer /tmp/$$
rm /tmp/$$
Source
I use this with some frequency:
$ ls -altrh --time-style=+%D | grep $(date +%D)
After going through many posts I found the best one that really works
find $file_path -type f -name "*.txt" -mtime -1 -printf "%f\n"
This prints only the file name like
abc.txt not the /path/tofolder/abc.txt
Also also play around or customize with -mtime -1
This worked for me. Lists the files created on May 30 in the current directory.
ls -lt | grep 'May 30'
Use ls or find to have all the files that were created today.
Using ls : ls -ltr | grep "$(date '+%b %e')"
Using find : cd $YOUR_DIRECTORY; find . -ls 2>/dev/null| grep "$(date '+%b %e')"
find ./ -maxdepth 1 -type f -execdir basename '{}' ';' | grep `date +'%Y%m%d'`
You can use find and ls to accomplish with this:
find . -type f -exec ls -l {} \; | egrep "Aug 26";
It will find all files in this directory, display useful informations (-l) and filter the lines with some date you want... It may be a little bit slow, but still useful in some cases.
Just keep in mind there are 2 spaces between Aug and 26. Other wise your find command will not work.
find . -type f -exec ls -l {} \; | egrep "Aug 26";
If you're did something like accidentally rsync'd to the wrong directory, the above suggestions work to find new files, but for me, the easiest was connecting with an SFTP client like Transmit then ordering by date and deleting.
To get file before 24 hours execute below command:
find . -type f -mtime 1 -exec ls -l {} \;
To get files created today execute below command:
find . -type f -mtime -1 -exec ls -l {} \;
To Get files created before n days before, where +2 is before 2 days files in below command:
find . -type f -mtime +2 -exec ls -l {} \;

Resources