Error while executing bash script - bash

I have a file named 1.txt which contains numbers, like 2, 30,20,1 etc. I am trying to compare each number in this text file with a numeric value 20 and I would like to run a command if the value is equal to 20, otherwise exit.
My code is given below. When I try to run the bash script, getting error as
----------
email.sh: line 2: [[2: command not found
email.sh: line 2: [[1: command not found
for f in $( cat 1.txt ); do
if [[$f -eq "20"]];
then
echo "sucess"
fi
done

You should have space after the [[ in the if
if [[ "$f" -eq "20" ]];
Example
$ if [[ "$f" -eq "20" ]]; then echo "sucess"; fi
sucess
Why?
In bash the [[ ]] construct is called extended test command, and you always need to separate tokens in any language with spaces.

There is an error in your if, syntax error. try including space:
#!/bin/bash
for f in $( cat 1.txt ); do
if [ $f -eq "20" ];
then
echo "sucess"
fi
done

Related

check if passed arguments to bash script is same as a filename

I want to check if the argument passed while executing the script matches the prefix of a filename in my directory. I m facing binary operator expected error with my code. Does any body have any alternative approach ?
./test.sh abc
fucn_1(){
if [ -e $file_name* ] ; then
func_2
else
echo "file not found"
exit
fi
}
if [ $1 == abc ];
then
file_name=`echo $1`
fucn_1
elif [ $1 == xyz ];
then
file_name=`echo $1`
fucn_1
while running I m passing abc as the argument such that then script can then check if the filenames starting with 'abc' is present or not in the directory.
the dir has files :-
abc_1234.txt
abc_2345.txt
The glob $file_name* expands to a list of files. You ran [ -e abc_1234.txt abc_2345.txt ] which gives an error, since [ -e expects only one file, not two.
Try something like ...
#! /usr/bin/env bash
shopt -s nullglob
has_args() { (( "$#" > 0 )); }
if has_args "$1"*; then
echo "$1 is a prefix of some file or dir"
else
echo "$1 is not a prefix of any file or dir"
fi

Checking input with an if statement (bash)

I am trying to write a file that mimics the cat -n bash command. It is supposed to accept a filename as input and if no input is given print a usage statement.
This is what I have so far but I am not sure what I am doing wrong:
#!/bin/bash
echo "OK"
read filename
if [ $filename -eq 0 ]
then
echo "Usage: cat-n.sh file"
else
cat -n $filename
fi
I suggest to use -z to check for empty variable $filename:
if [ -z $filename ]
See: help test

Bash scripting: syntax error near unexpected token `done'

I am new to bash scripting and I have to create this script that takes 3 directories as arguments and copies in the third one all the files in the first one that are NOT in the second one.
I did it like this:
#!/bin/bash
if [ -d $1 && -d $2 && -d $3 ]; then
for FILE in [ ls $1 ]; do
if ! [ find $2 -name $FILE ]; then
cp $FILE $3
done
else echo "Error: one or more directories are not present"
fi
The error I get when I try to execute it is: "line 7: syntax error near unexpected token `done' "
I don't really know how to make it work!
Also even if I'm using #!/bin/bash I still have to explicitly call bash when trying to execute, otherwise it says that executing is not permitted, anybody knows why?
Thanks in advance :)
Couple of suggestions :
No harm double quoting variables
cp "$FILE" "$3" # prevents wordsplitting, helps you filenames with spaces
for statement fails for the fundamental reason -bad syntax- it should've been:
for FILE in ls "$1";
But then, never parse ls output. Check [ this ].
for FILE in ls "$1"; #drastic
Instead of the for-loop in step2 use a find-while-read combination:
find "$1" -type f -print0 | while read -rd'' filename #-type f for files
do
#something with $filename
done
Use lowercase variable names for your script as uppercase variables are reserved for the system. Check [this].
Use tools like [ shellcheck ] to improve script quality.
Edit
Since you have mentioned the input directories contain only files, my alternative approach would be
[[ -d "$1" && -d "$2" && -d "$3" ]] && for filename in "$1"/*
do
[ ! -e "$2/${filename##*/}" ] && cp "$filename" "$3"
done
If you are baffled by ${filename##*/} check [ shell parameter expansion ].
Sidenote: In linux, although discouraged it not uncommon to have non-standard filenames like file name.
Courtesy: #chepner & #mklement0 for their comments that greatly improved this answer :)
Your script:
if ...; then
for ...; do
if ...; then
...
done
else
...
fi
Fixed structure:
if ...; then
for ...; do
if ...; then
...
fi # <-- missing
done
else
...
fi
If you want the script executable, then make it so:
$ chmod +x script.sh
Notice that you also have other problems in you script. It is better written as
dir1="$1"
dir2="$2"
dir3="$3"
for f in "$dir1"/*; do
if [ ! -f "$dir2/$(basename "$f")" ]; then
cp "$f" "$dir3"
fi
done
this is not totally correct:
for FILE in $(ls $1); do
< whatever you do here >
done
There is a big problem with that loop if in that folder there is a filename like this: 'I am a filename with spaces.txt'.
Instead of that loop try this:
for FILE in "$1"/*; do
echo "$FILE"
done
Also you have to close every if statement with fi.
Another thing, if you are using BASH ( #!/usr/bin/env bash ), it is highly recommended to use double brackets in your test conditions:
if [[ test ]]; then
...
fi
For example:
$ a='foo bar'
$ if [[ $a == 'foo bar' ]]; then
> echo "it's ok"
> fi
it's ok
However, this:
$ if [ $a == 'foo bar' ]; then
> echo "it's ok";
> fi
bash: [: too many arguments
You've forgot fi after the innermost if.
Additionally, neither square brackets nor find do work this way. This one does what your script (as it is now) is intended to on my PC:
#!/bin/bash
if [[ -d "$1" && -d "$2" && -d "$3" ]] ; then
ls -1 "$1" | while read FILE ; do
ls "$2/$FILE" >/dev/null 2>&1 || cp "$1/$FILE" "$3"
done
else echo "Error: one or more directories are not present"
fi
Note that after a single run, when $2 and $3 refer to different directories, those files are still not present in $2, so next time you run the script they will be copied once more despite they already are present in $3.

bash script to take file as input and show all lines with no

Right. Basically what I want to achieve is i am trying to write a bash script which will take file as input argument and then load that file in the script and show all the lines in that file with the numbers bulletin. how can i do that.
i have tried nl -ba teat file but its not working
1 hii
2 whats up
3 how are you today
4 where have you been
5 whats going on
this is the sript i have written
#!/bin/bash
if [ $# == 0 ]; then
echo "ivalid argument"
elif [ $1 == $file ]; then
while read line
do
echo `nl $Line`
done
else
echo "wtf"
fi
See below modified script that does the job without using "nl":
#!/bin/bash
if [ -z "$1" ]; then
echo "ivalid argument"
exit 1;
fi;
cnt=1;
while read line; do
echo "$cnt $line";
((cnt++));
done<"$1";
I don't know, what
[ $1 == $file ]
is supposed to mean in your script, since you don't set a variable file anywhere, but here is one solution:
#!/bin/bash
nl -ba {$1?Tell me the name of the file or I will kick you}

Distinguish different type of input (BASH)

I have a script that must be able to accept both by files and stdin on the first argument. Then if more or less than 1 arguments, reject them
The goal that I'm trying to accomplish is able to accpet using this format
./myscript myfile
AND
./myscript < myfile
What I have so far is
if [ "$#" -eq 1 ]; then #check argument
if [ -t 0 ]; then #check whether input from keyboard (read from github)
VAR=${1:-/dev/stdin} #get value to VAR
#then do stuff here!!
else #if not input from keyboard
VAR=$1
if [ ! -f "$VAR" ]; then #check whether file readable
echo "ERROR!"
else
#do stuff heree!!!
fi
fi
fi
The PROBLEM is when I tried to say
./myscript < myfile
it prints
ERROR!
I dont know whether this is the correct way to do this, I really appreciate for suggestion or the correct code for my problem. Thank you
#!/bin/bash
# if nothing passed in command line pass "/dev/stdin" to myself
# so all below code can be made branch-free
[[ ${#} -gt 0 ]] || set -- /dev/stdin
# loop through the command line arguments, treating them as file names
for f in "$#"; do
echo $f
[[ -r $f ]] && while read line; do echo 'echo:' $line; done < $f
done
Examples:
$ args.sh < input.txt
$ args.sh input.txt
$ cat input.txt | args.sh

Resources