Bash script to iterate over directories and create subdirectory - arrays

I have the following code which creates an array and iterate over a directory and create a subdirectory under each of the element of an array.
#!/bin/bash
cd /var/www
dirs=$(find * -maxdepth 0 -type d)
for dir in "${dirs[#]}"; do
echo $dir
mkdir $dir/backups
done
While it echo's all the directories, it creates a directory only on the last element of the array. What can be the issue?

If you are on bash 4.4 particularly , you can use the readarray feature like bellow. Also using -maxdepth 0 seems not a good option - you probably need to use -maxdepth 1.
#!/bin/bash
cd /var/www
readarray -t -d'' dirs < <$(find . -maxdepth 1 -type d -print0)
for dir in "${dirs[#]}"; do
echo $dir
mkdir $dir/backups
done
But in case you can do the whole thing just with find and mkdir -v (verbose):
$ find . -maxdepth 1 -type d -name 'a*'
./appsfiles
$ find . -maxdepth 1 -type d -name 'a*' -exec mkdir -v {}/backup \;
mkdir: created directory './appsfiles/backup'
Using mkdir -v you get verbose messages from mkdir and you can skip the echo.
If you need the echo anyway, you can do it like:
$ find . -maxdepth 1 -type d -name 'a*' -exec bash -c 'echo $0 && mkdir -v $0/backup' {} \;
./appsfiles
mkdir: created directory './appsfiles/backup'

The issue the array initialization - change it to:
dirs=($(find * -maxdepth 0 -type d))
However, the above statement can be problematic if you have directories that have white spaces in them.
You can use a simple glob instead - it handles white spaces too:
cd /var/www
dirs=(*/)
for dir in "${dirs[#]}"; do
: your code
done

Related

bash - using array with find command

I want to append found directories to array.
#!/bin/bash
FILES=()
find . ! \( \( -path './android/out' -o -path './.repo' \) -prune \) -type d -name prebuilts | while read file; do
echo "FILES -->$file"
FILES+=("$file")
done
echo "num of FILES: ${#FILES[#]}"
echo "FILES: ${FILES[#]}"
but result as below:
FILES -->./android/test/vts/prebuilts
FILES -->./android/system/apex/shim/prebuilts
FILES -->./android/system/sepolicy/prebuilts
FILES -->./android/vendor/tvstorm/prebuilts
FILES -->./android/vendor/dmt/prebuilts
FILES -->./android/kernel/prebuilts
FILES -->./android/prebuilts
FILES -->./android/developers/build/prebuilts
FILES -->./android/external/selinux/prebuilts
FILES -->./android/development/vndk/tools/header-checker/tests/integration/version_script_example/prebuilts
num of FILES: 0
FILES:
Why does num of array is 0?
You are populating the array after |, i.e. in a subshell. Changes from the subshell don't propagate to the parent shell.
Use process substitution instead:
while read file; do
echo "FILES -->$file"
FILES+=("$file")
done < <(find . ! \( \( -path './android/out' -o -path './.repo' \) -prune \) -type d -name prebuilts)
If you don't need job control, you can also shopt -s lastpipe to run the last command in a pipeline in the current shell.

How to make this script work but search for empty files in any directory instead of current directory?

#!/bin/bash
n=0
for f in *; do
[[ -f "$f" ]] && { echo "$f"; ((n++)); }
done
echo :Number of empty files: $n"
currently it checks the current directory for empty files, I would like it to search for empty files in any directory. Any ideas?
Recursively searches for empty files in current directory and below:
find . -empty -type f
Recursively lists empty files in specified directory and below and reports total
findempty
#!/bin/bash
echo :Number of empty files: `find $1 -empty -type f | tee /dev/tty | wc -l`
Example Usage
findempty /tmp
Example Output
/tmp/source/fb/b
/tmp/source/fb/a
/tmp/source/fb/c
/tmp/source/fa/b
/tmp/source/fa/a
/tmp/source/fa/c
/tmp/source/fc/b
/tmp/source/fc/a
/tmp/source/fc/c
/tmp/dest/source/fb/b
/tmp/dest/source/fa/b
/tmp/dest/source/fc/b
:Number of empty files: 12

exiting a shell script from a c program compiled from the same script

I've written the following shell script to compile and execute a c program and then to do some other operations.
#!/bin/sh
#
#FIRST SCRIPT
#
clear
echo "-----STARTING COMPILATION-----"
#echo $1
name=$1
#echo $name
find . -iname $name -maxdepth 1 -exec cp {} $name \;
new_file="tempwithfile.adb"
cp $name $new_file
cp $name1 $name
echo "compiling"
dir >filelist.txt
gcc writefile.c
run_file="run_file.txt"
echo $name > $run_file
./a.out
echo ""
echo "cleaning"
echo ""
make clean
make -f makefile
Can I stop the execution of the shell script if a particular condition is met in the c program? For e.g, if I am searching for a file from the program and i didn't find it, then I don't have to execute the rest of the shell script. Is it possible?
As ManĂ¼l said, you need to return a value from the main() function in the C code.
Then you can do this in the script:
./a.out
if [ $? -ne 0 ]
...

How do I control evaluation order?

For example, cd (echo ..) works in powershell, but how do I get it working in batch (it evaluates the echo first, and so the command is effectively cd ..)? mycommand.exe (ls -fi *.hs -exclude \"#*\" -name -r) is what I'm actually trying to convert (it sends a, completed, filtered file listing to mycommand).
setlocal enabledelayedexpansion
set LIST=
for /r %%F in (*.hs) do (
set "FN=%%F"
if not "!FN:~0,1!"=="#" set LIST=!LIST! "%%F"
)
mycommand.exe !LIST!
would be a rough translation.
add the $ symbol to evaluate the commands in the parens first:
mycommand.exe $(ls -fi *.hs -exclude \"#*\" -name -r)
or
ls -fi *.hs -exclude \"#*\" -name -r | mycommand.exe
If you want to execute the command for each item returned from your ls, you can:
ls -fi *.hs -exclude \"#*\" -name -r | %{mycommand.exe $_ }

How do I sort a directory full of pictures into sub-directories based on the image name?

I want to take all of the files in /media/mdrive/dump/:
1COD-234355.jpg
MAK-LXT218.jpg
ZIR-CON145.jpg
And create and sort them into the following directories:
/media/mdrive/dump/1/1COD-234355.jpg
/media/mdrive/dump/M/MAK-LXT218.jpg
/media/mdrive/dump/Z/ZIR-CON145.jpg
How would I do that?
This script takes a directory as the first argument and performs what you need:
#!/bin/bash
DIR="$1"
if [ -z "$DIR" ]; then
echo >&2 "Syntax: $0 <directory>"
exit 1
fi
if [ ! -d "$DIR" ]; then
echo >&2 "\"$DIR\" is not a directory"
exit 1
fi
cd "$DIR"
for file in *.jpg *.JPG; do
first=${file::1}
mkdir -p $first && mv $file $first/;
done
head -c xx will return the first xx characters of its input (here, the filename). mkdir -p will skip directory creation if it already exists.
to make two directories you could try something like
dir "/media/mdrive/dump/1/" :: CD would also work here
mkdir folder 1
mkdir folder 2
from here I think you can continue with your IF statements and so forth.
all you need to do is set the dir commands with the Direct path takes the guess work out.
then to check each just do:
start explorer.exe "the folder's path here"
it should open the folder to view the files

Resources