Passing ls command to a for loop breaks when trying to use command line arguments - bash

Im writing a simple script to list all files in a directory and whether each file is in fact a file or if it is a directory. If it is a directory then it outputs how many files are in the directory.
#!/bin/bash
for filename in $(ls)
do
if [ -f "$filename" ]
then
printf "$filename - file\n"
fi
if [ -d "$filename" ]
then
count=$(ls "$filename" | wc -l)
printf "$filename - directory $count files\n"
fi
done
This works perfectly fine. But if I try to pass a command line argument (directory name) to ls then the script doesn't work. Does anyone know what causes this to break. Example below.
#!/bin/bash
for filename in $(ls $1)
do
if [ -f "$filename" ]
then
printf "$filename - file\n"
fi
if [ -d "$filename" ]
then
count=$(ls "$filename" | wc -l)
printf "$filename - directory $count files\n"
fi
done

$filename exists in directory/$filename. And you are check $filename in current (./) directory.
You should check against directory/$filename
if [ -z $1 ]; then
echo USAGE: basename $0 directory
exit
else
directory=$1
fi
...
for ...
if [ -f "$directory/$filename" ]; then
...
...

When you are passing directory as argument you shouldn't check files $filename but $1/$filename.
If you are sure that there will always be an argument you should use something like:
#!/bin/bash
for filename in $(ls "$1")
do
if [ -f "$1/$filename" ]
then
printf "$1/$filename - file\n"
fi
if [ -d "$1/$filename" ]
then
count=$(ls "$1/$filename" | wc -l)
printf "$1/$filename - directory $count files\n"
fi
done
If dirname as argument is optional you should check if there is argument and process as you want. My suggestion:
#!/bin/bash
if [ -z ${1+x} ];
then
echo "No argument";
else
echo "There is argument";
cd $1;
fi
for filename in $(ls)
do
if [ -f "$filename" ]
then
printf "$filename - file\n"
fi
if [ -d "$filename" ]
then
count=$(ls "$filename" | wc -l)
printf "$filename - directory $count files\n"
fi
done

Related

Counting directories and files in bash

Simple counting dirs and files does not work. I am checking each file by -f and -d flag.
Where is a problem?
LOCATION=$1
for FILE in $(ls $LOCATION | egrep '^.{0,3}$');
do
echo "$FILE"
if [ -f $FILE ]
then
echo "its a file"
fi
if [ -d $FILE ]
then
echo "its a dir"
fi
done
shopt -s dotglob # count hidden files
for file in "$LOCATION/"*; do
[[ -f $file ]] && ((f++))
[[ -d $file ]] && ((d++))
done
echo "${d:-0} dirs"
echo "${f:-0} files"
without involving external utilities

Unix Bash - Copy files from a source folder recursively to destination/*file_extension*(ex. “txt”) folder

This is my code, something in the rec_copy() function isn't working properly, probably this line:
cp $1/$f $HOME/$2/$dest
The extension named folders are created in the destination folder but the files are not copied there. Can you help me?
#!/bin/bash
if [ $# -ne 2 ]
then
echo "Usage: $0 <source> <destination>"
exit
fi
if [ ! -d $1 ]
then
echo "Source folder does not exist"
exit
fi
if [ -d $2 ]
then
rm -r $2
mkdir $2
else
mkdir $2
fi
extension=`ls -l $1 | grep -v "^d" | awk '{ print $10; }' | sed 's/^.*\.//g'`
for f in $extension
do
if [ ! -d $1/$f ]
then
mkdir $2/$f
fi
done
rec_copy(){
folder=`ls $1`
for f in $folder
do
dest=`echo "$f" | sed 's/.*\.//g'`
if [ -f $1/$f ]
then
cp $1/$f $HOME/$2/$dest
elif [ -d $1/$f ]
then
rec_copy $1/$f
fi
done
}
rec_copy $1
Here is the answer in case someone ever needs it:
#!/bin/bash
if [ $# -ne 2 ]
then
echo "Usage: $0 <izvor> <destinacija>"
exit
fi
if [ ! -d "$1" ]
then
echo "Izvorniot folder ne postoi"
exit
fi
if [ -d "$2" ]
then
rm -r "$2"
mkdir "$2"
else
mkdir "$2"
fi
extension=`ls -l "$1" | grep -v "^d" | awk '{ print $10; }' | sed 's/^.*\.//g' | sort -u`
for f in $extension
do
if [ ! -d "$1/$f" ]
then
mkdir "$2/$f"
fi
done
rec_copy(){
folder=`ls "$1"`
for f in $folder
do
dest=`echo "$f" | sed 's/.*\.//g'`
to=`cp "$1/$f" "$2/$dest"`
if [ -f "$1/$f" ]
then
echo "$to"
elif [ -d "$1/$f" ]
then
rec_copy "$1/$f" "$2"
fi
done
}
rec_copy "./$1" "./$2"

Unix write to file creating new line only

I have the following code
#!/bin/bash
output= cat $1 | sed s/$2/$3/
if [ -f "$1" ]
then
echo $output > "$1"
echo "Done"
fi
Arguments:
1 is file
2 old word
3 new word to replace
File Permission is 777 and for some reason the code will replace the current file with a newline and that's it. Any possible reason for this issue?
Try:
#!/bin/bash
output=`cat $1 | sed s/$2/$3/`
if [ -f "$1" ]
then
echo $output > "$1"
echo "Done"
fi

Separate Directories from Files with "----" Bash Scripting

I want to separate directories from files in a list. I would like them to appear as follows:
DirectoryName1
DirectoryNameA
DirectoryName_Two
--
FileName1
FileNameA
FileName_Two
Basically, I want two or three dashes in between my directories and files.
Here is what the following code looks like.
DirectoryName1
DirectoryNameA
DirectoryName_Two
FileName1
FileNameA
FileName_Two
Here is my code:
#!/bin/bash
if [[ $# -ge 1 ]]; then
cd "$1" 2> /dev/null
if [[ $? = 1 ]]; then
echo "Please enter a valid directory."
else
ls -a | sort -k 1 | awk '{printf "(%d) %s\n", NR, $0;}'
fi
else
ls -a | sort -k 1| awk '{printf "(%d) %s\n", NR, $0;}'
fi
Here's one possible solution:
#!/bin/bash
if [[ $# -ge 1 ]]; then
dir_to_list=$1
if [[ ! -d ${dir_to_list} ]]; then
echo "Please enter a valid directory."
exit
fi
else
dir_to_list="."
fi
files=`ls --group-directories-first $dir_to_list`
DIRS="TRUE"
i=0
for f in ${files}; do
if [[ ${DIRS} == "TRUE" && ! -d ${dir_to_list}/${f} ]]; then
# First non-directory entry
echo ----
DIRS="FALSE"
fi
(( i++ ))
echo ${i}. ${f}
done
Cheers
Update: fixed bug for listing other directories

Bash script loop through subdirectories and write to file

I have no idea I have spent a lot of hours dealing with this problem. I need to write script. Script should loop recursively through subdirectories in current directory. It should check files count in each directory. If file count is greater than 10 it should write all names of these file in file named "BigList" otherwise it should write in file "ShortList". This should look like
---<directory name>
<filename>
<filename>
<filename>
<filename>
....
---<directory name>
<filename>
<filename>
<filename>
<filename>
....
My script only works if subdirecotries don't include subdirectories in turn.
I am confused about this. Because it doesn't work as I expect. It will take less than 5 minutes to write this on any programming language for my.
Please help to solve this problem , because I have no idea how to do this.
Here is my script
#!/bin/bash
parent_dir=""
if [ -d "$1" ]; then
path=$1;
else
path=$(pwd)
fi
parent_dir=$path
loop_folder_recurse() {
local files_list=""
local cnt=0
for i in "$1"/*;do
if [ -d "$i" ];then
echo "dir: $i"
parent_dir=$i
echo before recursion
loop_folder_recurse "$i"
echo after recursion
if [ $cnt -ge 10 ]; then
echo -e "---"$parent_dir >> BigList
echo -e $file_list >> BigList
else
echo -e "---"$parent_dir >> ShortList
echo -e $file_list >> ShortList
fi
elif [ -f "$i" ]; then
echo file $i
if [ $cur_fol != $main_pwd ]; then
file_list+=$i'\n'
cnt=$((cnt + 1))
fi
fi
done
}
echo "Base path: $path"
loop_folder_recurse $path
I believe that this does what you want:
find . -type d -exec env d={} bash -c 'out=Shortlist; [ $(ls "$d" | wc -l) -ge 10 ] && out=Biglist; { echo "--$d"; ls "$d"; echo; } >>"$out"' ';'
If we don't want either to count subdirectories to the cut-off or to list them in the output, then use this version:
find . -type d -exec env d={} bash -c 'out=Shortlist; [ $(ls -p "$d" | grep -v "/$" | wc -l) -ge 10 ] && out=Biglist; { echo "--$d"; ls -p "$d"; echo; } | grep -v "/$" >>"$out"' ';'

Resources