bash function dont recognize input - bash

I seem to have some problems executing this bash function from the terminal,
function sort () {
if [ "$#" -ne 1 ];
then
word="$arg1"
isolated="$arg2"
file="output/$word _ $isolated_matches"
else
word="$arg1"
file="output/$word_matches"
fi
echo "$word"
echo "$file"
cat "$file" | while read line;
do
output=$(awk 'BEGIN{IGNORECASE=1} /"$word"/ {print NR, $0}' "$line");
if [ $[#output] -ne 0 ];
then
echo "File: " "$line";
echo "----------------------------------------------------";
echo "$output";
fi
echo $'\n';
done
I source the script in the terminal, and when i execute
sort a a
My output becomes :
output
cat: output/ Is a directory
Why does it not recognize the input I am given it?

Just check this change.
#!/bin/bash
function sort () {
if [ "$#" -ne 1 ];
then
word=$1
isolated=$2
file="output/${word}_${isolated}_matches"
else
word="$1"
file="output/${word}_matches"
fi
touch "$file"
echo "word : $word"
echo "file : $file"
cat "$file" | while read line;
do
output=$(awk -v word="$word"; BEGIN{IGNORECASE=1} /"$word"/ {print NR, $0}' "$line");
if [ -n "$output" ];
then
echo "File: " "$line";
echo "----------------------------------------------------";
echo "$output";
fi
echo $'\n';
done
}
OUTPUT
smily#Machine MINGK64 /d/test
$ sh testbash.sh
word : a
file : output/a_a_matches

Related

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"

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

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

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 - sometimes creates only empty output

I am trying to create a bash dictionary script that accepts first argument and creates file named after that, then script accepts next arguments (which are files inside same folder) and outputs their content into file (first argument). It also sorts, deletes symbols etc., but main problem is, that sometimes ouptut file is empty (I am passing one non empty file and one non existing file), after deleting and running script few more times it is sometimes empty sometimes not.
#!/bin/bash
numberoffileargs=$(( $# - 1 ))
exitstat=0
counterexit=0
acceptingstdin=0;
> "$1";
#check if we have given input files given
if [ "$#" -gt 1 ]; then
#for cycle going through input files
for i in "${#:2}"
do
#check whether input file is readable
if [ -r "${i}" ]; then
cat "${i}" >> "$1"
#else redirect to standard output
else
exitstat=2
counterexit=$((counterexit + 1))
echo "file does not exist" 1>&2
fi
done
else
echo "stdin code to be done"
acceptingstdin=1
#stdin input to output file
#stdin=$(cat)
fi
#one word for each line, alphabetical sort, alphabet only, remove duplicates
#all lowercase
#sort -u >> "$1"
if [ "$counterexit" -eq "$numberoffileargs" ] && [ "$acceptingstdin" -eq 0 ]; then
exitstat=3
fi
cat "$1" | sed -r 's/[^a-zA-Z\-]+/ /g' | tr A-Z a-z | tr ' ' '\n' | sort -u | sed '/^$/d' > "$1"
echo "$numberoffileargs"
echo "$counterexit"
echo "$exitstat"
exit $exitstat
Here is your script with some syntax improvement. Your trouble came from the fact that the dictionary was both on input and output on your pipeline; I added a temp file to fix it.
#!/bin/bash
(($# >= 1)) || { echo "Usage: $0 dictionary file ..." >&2 ; exit 1;}
dict="$1"
shift
echo "Creating $dict ..."
>| "$dict" || { echo "Failed." >&2 ; exit 1;}
numberoffileargs=$#
exitstat=0
counterexit=0
acceptingstdin=0
if (($# > 0)); then
for i ; do
#check whether input file is readable
if [ -r "${i}" ]; then
cat "${i}" >> "$dict"
else
exitstat=2
let counterexit++
echo "file does not exist" >&2
fi
done
else
echo "stdin code to be done"
acceptingstdin=1
fi
if ((counterexit == numberoffileargs && acceptingstdin == 0)); then
exitstat=3
fi
sed -r 's/[^a-zA-Z\-]+/ /g' < "$dict" | tr '[:upper:]' '[:lower:]' | tr ' ' '\n' |
sort -u | sed '/^$/d' >| tmp$$
mv -f tmp$$ "$dict"
echo "$numberoffileargs"
echo "$counterexit"
echo "$exitstat"
exit $exitstat
The pipeline might be improved.

Shell script for generating HTML out put

The following script is generating the desired out put but not redirecting the result to /home/myuser/slavedelay.html
#!/bin/bash
host=<ip>
echo $host
user=usr1
password=mypass
threshold=300
statusok=OK
statuscritical=CRITICAL
for i in ert7 ert9
do
echo "<html>" > /home/myuser/slavedelay.html
if [ "$i" == "ert7" ]; then
slvdelay=`mysql -u$user -p$password -h<ip> -S /backup/mysql/mysql.sock -e 'show slave status\G' | grep Seconds_Behind_Master | sed -e 's/ *Seconds_Behind_Master: //'`
if [ $slvdelay -ge $threshold ]; then
echo "<tr><td>$i</td><td>CRITICAL</td>" >> /home/myuser/slavedelay.html
echo "<tr><td>$i</td><td>CRITICAL</td>"
else
echo "<tr><td>$i</td><td>OK</td>" >> /home/myuser/slavedelay.html
echo "<tr><td>$i</td><td>OK</td>"
fi
fi
done
echo "</html>" >> /home/myuser/slavedelay.html
If I cat the output file /home/myuser/slavedelay.html it gives.
<html>
</html>
Execution result :
sh slave_delay.sh
<tr><td>sdb7</td><td>OK</td>
Each time through the loop you're emptying the output file because of the command
echo "<html>" > /home/myuser/slavedelay.html
So the first iteration writes the <tr> row to the file, then the next iteration overwrites the file and doesn't write those lines because $i isn't ert7.
Change it to:
for i in ert7 ert9
do
if [ "$i" == "ert7" ]; then
echo "<html>" > /home/myuser/slavedelay.html
slvdelay=`mysql -u$user -p$password -h<ip> -S /backup/mysql/mysql.sock -e 'show slave status\G' | grep Seconds_Behind_Master | sed -e 's/ *Seconds_Behind_Master: //'`
if [ $slvdelay -ge $threshold ]; then
echo "<tr><td>$i</td><td>CRITICAL</td>"
else
echo "<tr><td>$i</td><td>OK</td>"
fi | tee -a /home/myuser/slavedelay.html
echo "</html>" >> /home/myuser/slavedelay.html
fi
done
Replace :
if [ "$i" == "ert7" ];
with:
if [ "$i" = "ert7" ];
You use = operator in test also.

Resources