bash: if statement with multiple checks - bash

In my bash script I need to check if the first CLI is defined and the second one is an existing file
Here is what I have:
if [!$2] && [! -f $1 ]; then
....
fi
So $2 should exist (string) and $1 should be the existing file on the filesystem!
Any suggestions ?

If by suggestions you mean what do I need to make it work, then what you need to do is to add spaces around brackets. Also it is good to quote the variables:
if [ -n "$2" ] && [ ! -f "$1" ]; then
...
fi
From man test:
-n STRING
the length of STRING is nonzero

Related

Compare $1 with another string in bash

I've spent 2 hours with an if statement, that never works like I want:
#should return true
if [ "$1" == "355258054414904" ]; then
Here is the whole script:
#!/bin/bash
param=$1
INPUT=simu_900_imei_user_pass.csv
OLDIFS=$IFS
IFS=,
[ ! -f $INPUT ] && { echo "$INPUT ime not found"; exit 99; }
while read imei email pass
do
echo "First Parameter-IMEI: $1"
if [ "$1" == "355258054414904" ]; then
echo "GOOD"
fi
done < $INPUT
IFS=$OLDIFS
This is the output of the script:
First Parameter-IMEI: 355258054414904
First Parameter-IMEI: 355258054414904
First Parameter-IMEI: 355258054414904
I have seen a lot of pages about the subject, but I can't make it work :(
EDIT: I Join the content of csv for better understanding ! Tx for your help !
4790057be1803096,user1,pass1
355258054414904,juju,capp
4790057be1803096,user2,pass2
358854053154579,user3,pass3
The reason $1 does not match is because $1 means the first parameter given to the script on the command line, while you want it to match the first field read from the file. That value is in $imei.
You probably meant:
if [ "$imei" == "355258054414904" ]; then
echo "GOOD"
fi
Since it is inside the loop where you read input file line by line.
To check content of $1 use:
cat -vet <<< "$1"
UPDATE: To strip \r from $1 have this at top:
param=$(tr -d '\r' <<< "$1")
And then use "$param" in rest of your script.
To test string equality with [ you want to use a single '=' sign.

File is found even though folder is empty using bash - test whether a directory is empty

I want to see if files exist in a certain folder and if they exist run certain event else skip this. Bash see files in my empty folder.
I tried a few different ways and all show that a file exits.
$ [ -f ] && echo "Found" || echo "Not found"
Found
$ [ -r ] && echo "Found" || echo "Not found"
Found
$ [ -e ] && echo "Found" || echo "Not found"
Found
Whereas it does not:
$ ls -lrt
total 0
What am I missing here?
My actual code is:
get_last_parsed_file_time ()
{
if [ -s "$DATA_DIR$EPG_XML_FILES" ]
then
NEWEST_FILE=$( ls -tr | tail -1 )
LAST_PARSED_TIME=$( stat -c %Y $NEWEST_FILE )
else
NO_FILE=1
fi
}
[ -f filename ] checks if filename is a file that exists.
[ str ] checks whether str is non-empty.
In your case, str is -f, but it still just checks whether string "-f" is nonempty, which it obviously isn't (it's two characters, a dash and an "f").
This is especially puzzling in the case of [ -f $filename ]. When $filename is empty and unquoted, the command will become [ -f ] and will be true. Always quote your variables.
that other guy's answer explains why [ -f ] doesn't work.
More generally, it is important to note that you cannot pass globs (filename patterns such as * to a bash file-test operator such as -f. The file-test operators expect a single, literal filename or file path (either as a string literal or as a string stored in a variable).
[[ -f '/path/to/file' ]] # correct
[[ -f /path/to/* ]] # WRONG
Here's a snippet that tests whether a folder is empty, i.e. whether it contains ANY items - whether files, hidden files, or subfolders:
folder='/path/to/folder'
[[ -n $(ls -A "$folder" | head -n 1) ]] && echo "NON-empty" || echo "EMPTY"
To only consider non-hidden items, remove -A from the ls command.
To quietly ignore the case where the input folder doesn't exist or is not accessible, append 2> /dev/null to the ls command.

bash passing arguments/parameters?

#!/bin/bash
traverse() {
local x=$1
if [ -d $x ]
then
lst=(`ls $x`)
for((i=${#lst[#]}; --i;)); do
echo "${lst[i]}"
done
else echo "not a directory"
fi
}
traverse
I want to pass a parameter such as "/path/to/this/directory/" when executing program but only works if I'm running the program in the same directory as my bash script file and any other parameter I pass is completely ignored.
the script is supposed to take a parameter and check if it's a directory and if it's a directory then list all the files/folders in descending order. If not display error message.
What is wrong with code, thanks!
This happens because $1 in the function refers to traverse's parameters, not your script's parameters.
To run your function once with each argument, use
for arg in "$#" # "$#" is also the default, so you can drop the 'in ..'
do
traverse "$arg"
done
If you in the future want to pass all the script's parameters to a function, use
myfunc "$#"
This is just the problem at hand, though. Other problems include not quoting your variables and using command expansion of ls, lst=(`ls $x`), instead of globs, lst=( "$x"/* )
You don't need to call ls for that. You can use this code:
traverse() {
local x="$1"
if [ -d "$x" ]; then
arr=( "$x/"* )
for ((i=${#arr[#]}; i>0; i--)); do
echo "${arr[$i]}"
done
else
echo "not a directory"
fi
}
"That other guy" has the right answer. The reason it always looks at the current directory:
you invoke traverse with no arguments
the $1 in the traverse function is empty, therefore $x is empty
the test is therefore [ -d ], and when [ is given 1 argument, it returns success if the argument is not empty. Your if command always executes the "true" block and ls $x is just ls when x is empty
Use [[ ... ]] with bash: it is smarter about empty arguments. Otherwise, quote your variables:
$ x=; [ -d $x ] && echo always true || echo not a directory
always true
$ x=; [[ -d $x ]] && echo always true || echo not a directory
not a directory
$ x=; [ -d "$x" ] && echo always true || echo not a directory
not a directory

BASH script accepting parameters

I have to write a script that accepts 1+ source files and destination directory as arguments. I've attempted to write an error message for filenames that contain spaces, but its getting an error when I enter more than 1 argument with a space in between as well. Any help would be appreciated.. This is what I wrote so far:
if [ "$#" -eq "$(echo "$#" | wc -w)" ]
then
echo "Invalid arguments. Filenames may not contain spaces."
echo "usage: bkup file1 [file2...] bkup_directory"
exit 13
fi
You MAY want to try:
if [ $filename == "*" "*" ]; then
echo your error message here
fi
for the testing of spaces in filenames.
As for actually getting the args
$1 is the variable for the first arg and $2 for the second and so on so something like this might work:
if [ $2 == "*" ]; then
echo NO NO NO NOT TODAY!!!
fi
this would check to see if the second argument says anything at all and so if it did we can assume that it is part of the file name (THIS WOULD ONLY WORK IF THE FILENAME IS THE LAST ARGUMENT) OR:
if [ $2 == "*" ]; then
fil=$1 + \
filename=&fil + $2
fi
this would automatically change their filename into an acceptable format for the system an you would not need an error message.
but i am also new to bash so this could not be what you are looking for or I could have the right idea and all this could be complete whooey..... But if I helped then I'm glad I could.

multiple if condition in unix

I am trying to run the below logic
if [-f $file] && [$variable -lt 1] ; then
some logic
else
print "This is wrong"
fi
It fails with the following error
MyScipt.ksh[10]: [-f: not found
Where 10th line is the if condition , I have put in .
I have also tried
if [-f $file && $variable -lt 1] ; then
which gives the same error.
I know this is a syntax mistake somehwere , but I am not sure , what is the correct syntax when I am using multiple conditions with && in a if block
[ is not an operator, it's the name of a program (or a builtin, sometimes). Use type [ to check. Regardless, you need to put a space after it so that the command line parser knows what to do:
if [ -f $file ]
The && operator might not do what you want in this case, either. You should probably read the bash(1) documentation. In this specific case, it seems like what you want is:
if [ -f $file -a $variable -lt 1 ]
Or in more modern bash syntax:
if [[ -f $file && $variable -lt 1 ]]
The [ syntax is secretly a program!
$ type [
[ is a shell builtin
$ ls -l $(which [)
-rwxr-xr-x 1 root root 35264 Nov 19 16:25 /usr/bin/[
Because of the way the shell parses (technically "lexes") your command line, it sees this:
if - keyword
[-f - the program [-f
$file] - A string argument to the [-f program, made by the value of $file and ]. If $file was "asdf", then this would be asdf]
And so forth, down your command. What you need to do is include spaces, which the shell uses to separate the different parts (tokens) of your command:
if [ -f "$file" ]; then
Now [ stands on its own, and can be recognized as a command/program. Also, ] stands on its own as an argument to [, otherwise [ will complain. A couple more notes about this:
You don't need to put a space before or after ;, because that is a special separator that the shell recognizes.
You should always "double quote" $variables because they get expanded before the shell does the lexing. This means that if an unquoted variable contains a space, the shell will see the value as separate tokens, instead of one string.
Using && in an if-test like that isn't the usual way to do it. [ (also known as test) understands -a to mean "and," so this does what you intended:
if [ -f "$file" -a "$variable" -lt 1 ]; then
Use -a in an if block to represent AND.
Note the space preceding the -f option.
if [ -f $file -a $variable -lt 1] ; then
some logic
else
print "This is wrong"
fi

Resources