I want to check if a file exists or not along with the no of lines = 4 in a single if condition . Can anyone help here.
if [[ -f report]] && [[`wc -l report` -eq 4 ]]; then
echo " Proceed further"
else
exit 1
fi
This is simpler:
{ [ `wc -l < report` -eq 4 ] || exit; } 2>/dev/null
echo " Proceed further"
Notes:
If report exists and is 4 lines long, then wc -l report
returns:
4 report
...which -eq can't understand. Instead do wc -l < report which
outputs an -eq-friendly:
4
There's no need to check if report exists, since the < redirection
will do that anyway, and returns the same error code.
More specific exit codes. If report does not exist, the exit code is 2. If report is 5 lines long, the exit code is 1.
Related
I have the following code:
DOMAIN="mydomain.net"
if [ "${DOMAIN}" != "null" ]; then
SSL_CUSTOM=$(echo ${DOMAIN}| grep -c 'myapi.com')
fi
echo $SSL_CUSTOM
This should simply echo 0 in the output, BUT it seems to exit after the SSL_CUSTOM condition line without throwing an exit code.
Here's the debug output:
+ DOMAIN=mydomain.net
+ '[' mydomain.net '!=' null ']'
++ echo mydomain.net
++ grep -c myapi.com
+ SSL_CUSTOM=0
I could really use an advice what am I doing wrong here. I spent hours on trying to track down the issue in this simple code.
Thanks
To follow up on my comment with an answer:
SSL_CUSTOM=$(echo ${DOMAIN}| grep -c 'myapi.com' || true)
# ...............................................^^^^^^^
That lets grep -c do what it does, but if no matches are found, the exit status of the pipeline will be "success"
grep exit status demo:
$ seq 1 8 | grep -c 0
0
$ echo $?
1
I'm not really sure what you are trying to accomplish, so I will fill the gaps with guesses. You have an echo at the end, giving something like 0 or 1. You are also mentioning exit codes.
I'm guessing that you want
exit $SSL_CUSTOM
as your last line.
I am writing a shell script to check two things at one time. The first condition is to check for the existence of a specific file and the second condition is to confirm that there is only one file in that directory.
I am using the following code:
conf_file=ls -1 /opt/files/conf.json 2>/dev/null | wc -l
total_file=ls -1 /opt/files/* 2>/dev/null| wc -l
if [ $conf_file -eq 1 ] && [ $total_file -eq 1 ]
then
echo "done"
else
echo "Not Done"
fi
It is returning the following error
0
0
./ifexist.sh: 4: [: -eq: unexpected operator
Not Done
I am probably doing a very silly mistake. Can anyone help me a little bit?
One of the reasons you should normally not parse ls is that you can get strange results when you have files with newlines. In your case that won't be an issue, because any file different from json.conf should make the test fail. However you should make the code counting the files be future-proof. You can use find for this.
Your code can be changed into
jsonfile="/opt/files/conf.json"
countfiles=$(find /opt/files -maxdepth 1 -type f -exec printf '.\n' \; | wc -l)
if [[ -f "${jsonfile}" ]] && (( "${countfiles}" == 1)); then
echo "Done"
else
echo "Not Done"
fi
When you say this:
conf_file=ls -1 /opt/files/conf.json 2>/dev/null | wc -l
That assigns the value "ls" to the variable conf_file, and then tries to run a command called "-1" and pipe the result to wc If you want to run a pipe sequence, you have to enclose it in $( ):
conf_file=$(ls -1 /opt/files/conf.json 2./dev/null | wc -l)
Next, when combining clauses in the test command ([), do it inside the command:
if [ $conf_file -eq 1 -a $total_file -eq 1 ]
However, there are better ways to do this. You can check if a file exists with "-f", and you can just check whether the output of ls matches what you expect, without creating variables or running other commands:
if [ -f /opt/files/conf.json -a "$(ls /opt/files/conf.*)" -eq "/opt/files/conf.json" ]
However, it is not a friendly practice to prohibit other files. In many cases, people might want to leave backup or test copies (conf.json.bak or conf.json.test), and there's no reason for you to block that.
I have a set of files at a directory. I need to exit out of my script if i don't find the pairs of files at a given time.
Let's say i have these 3 files at directory $SRC_DIR
file 1: apple_iphone_file.zip
file 2: apple_ipad_file.zip
file 3: apple_mac_file.zip
If these 3 set of files are present i am doing some post processing.
There can be multiple pairs like 2,3, OR N set of these 3 files (file1,file2,file3).
I should exit the script if the same set are not present for all 3 files.
I am planing to count file 1 and if it gives me 2 , i will check if the other two files (file 2 and file 3) also gives me same count , else i will exit.
Do you think , we can do in any other way too?
Any input is highly appreciated.
Code Tried
#!/usr/bin/ksh
file1_count=$(ls ${SRC_DIR}/apple_iphone_file.zip | wc -l)
file2_count=$(ls ${SRC_DIR}/apple_ipad_file.zip | wc -l)
file3_count=$(ls ${SRC_DIR}/apple_mac_file.zip | wc -l)
if [ "$file1_count" == "$file2_count" -a "$file2_count" == "$file3_count" ]; then
echo "Files count match"
else
echo "Files count don't match"
exit 1
fi
This is giving me the results. However, if the files aren't present (none of them) it still shows me "Count Match".
Two scripts, check and pre-process. In check, if the variables corresponding with all three files equal 1, run pre-process. The default action (which runs next if that fails) is to exit.
Pre-process finds all files in the directory, puts their names in an input stack, and then uses each name as input for the main function. The code between the two ed lines is an example; replace it with your own. After that, it exits.
check.sh:-
#!/bin/sh
find apple_iphone_file.zip && iphone=1
find apple_ipad_file.zip && ipad=1
find apple_mac_file.zip && mac=1
[ "${iphone}" -eq 1 ] && [ "${ipad}" -eq 1 ] && \
[ "${mac}" -eq 1 ] && ./pre-process.sh
exit 0
pre-process.sh:-
#!/bin/sh
next() {
[ -s stack ] && main
end
}
main() {
line=$(ed -s stack < edprint+.txt)
echo "${line}" | tr '[a-z]' '[A-Z]'
ed -s stack < edpop+.txt
next
}
end() {
rm -v ./stack
rm -v ./edprint+.txt
rm -v ./edpop+.txt
exit 0
}
find . -type -f > stack
cat >> edprint+.txt << EOF
1
q
EOF
cat >> edpop+.txt << EOF
1d
wq
EOF
There are so many possibilities.
One option:
my_counter=""
[ -f "file_name_1" ] && my_counter="x$my_counter"
[ -f "file_name_2" ] && my_counter="x$my_counter"
[ -f "file_name_3" ] && my_counter="x$my_counter"
if [ "${#my_counter}" -lt 2 ]; then
echo "Error"
else
echo "doing stuffs"
fi
You can easily add check for file, change lower and upper limit, and ev. doing more tests (in similar way) in series. Note: for shell scripts, I tend to copy paste, because the command are easy (low probability of refactoring), and often I find the need to add extra tests on specific cases.
I'm trying to run a shell command (currently either sh or bash) which connects to a database. Because the database is still 'warming up', the command fails.
So I was trying to do a loop (let's say ... 100 tries) and each time the command fails, wait 1 second and retry.
If there's an error, this is the start of the string that is dumped to stdout: Sqlcmd: Error: <snipped>
Here's what I've been trying:
for i in $(seq 1 100)
do
X='/opt/mssql-tools/bin/sqlcmd -E -S localhost -Q "<some sql statement> "'
if [[ $X == Sqlcmd: Error:* ]]
echo "."
then
break
fi
done
It's not working as I figure out the string comparison stuff with shell/bash ... but was more making sure if I was on the right track etc.
You could try something like:
while true ; do
if Sqlcmd xxx xxx xxx ; then break ; fi
# or:
Sqlcmd xx xxx xxx && break
sleep 1
done
You can also add a counter:
for ((n=100;n>0;n--)) ; do
Sqlcmd xxx xxx xxx
if [[ $? == 0 ]] ; then
break
fi
sleep 1
done
[[ $n == 0 ]] && echo Timeout && exit 1
I'm showing two different ways of testing the return value here, but the first one is preferred (if cmd ; then ... ; fi).
$? is the return value from the last command, which is 0 when it completed successfully. If it returns 0 even in case of error (which can happen for malformed programs), you can test the output with grep:
Sqlcmd xxx xxx 2>&1 | grep <error pattern> > /dev/null
if [[ $? != 0 ]] ; then break ; fi
Here we test $? != 0 because grep will return 0 when the error pattern has been found.
If you want to get the output result into a variable, run the command with X=$(Sqlcmd xxx xxx). Then you can use bash string comparison:
X=$(Sqlcmd xxx xxx)
if [[ "$X" =~ .*error.* ]] ; then
<handle error here>
fi
Note bash can match regexp, which makes it really handy at checking error types.
You can also use a switch/case construct:
case "$X" in
*Error:*) echo " Error detected " ;;
*) break ;;
esac
(Note the double ;;)
I ended up learning all the clues from #matthieu's post. This is what I ended up doing:
for i in $(seq 1 30)
do
/opt/mssql-tools/bin/sqlcmd -U sa -P <snip> -S localhost -Q "USE Master" 2>&1
if [[ $? != 0 ]]
then
# Failed
echo "."
sleep 1s
else
# worked!
break
fi
done
breakdown for those learning (like me)
execute a sql query using the sqlcmd command. Any errors via stderr (that's the 2 in 2>&1) will be redirected to the console stdout (that's the $1). REF: 2>&1 shell idiom.
the result status code is sent to $? (REF: what is bash dollar questionmark ?)
if it failed(any value that is NOT a zero), then sleep 1 sec and we'll try. Only re-try 30 times, though.
if we worked (value is zero), then stop trying and go on....
So there we have it! shell/bash shell 101 stuff. good luck!
I'm writing a very simple shell scripts that would looked at the log of all failed tests, and print out all the name of all files in the current directory that are in the log
1 #! /bin/sh
2 for file in *
3 do
4 echo "checking: $file"
5 if [$(grep $file failed.txt -c) -ne 0]
6 then
7 echo "$file FAILED"
8 fi
9 done
When I execute it, I get this error:
line 6: [0: command not found
Does anyone have any idea why?
Thanks!!
[ is actually a command in linux (like bash or cat or grep).
$(grep $file failed.txt -c) is a command substitution which in your case evaluated to 0. Thus the line now reads [0 -ne 0], which is interpreted as run a program called [0 with arguments -ne 0].
What you should write instead is [ $(grep $file failed.txt -c) -ne 0 ]. Shell scripts require that there be spaces between the opening and closing square braces. Otherwise you change the command that is executed (the closing ] indicates that there are no more arguments to be read.
So now the command evaluates to [ 0 -ne 0 ]. You can try executing this in your shell to see what happens. [ exits with a value of 0 if the expression is true and 1 if it is false. You can see the exit value by echoing $? (the exit value of the last command to be run).
Instead of testing the count, you can test the return code of grep:
if grep -q $file failed.txt &>/dev/null
The script can be
#!/bin/sh
for file in *; do
echo "checking: $file"
grep failed.txt $file && echo "$file FAILED"
done
or, as an one-liner in user shell command history:
for file in *; do { echo "checking: $file" && grep failed.txt $file && echo "$file FAILED"; done
in man grep
EXIT STATUS
The exit status is 0 if selected lines are found, and 1 if not found. If an error occurred the exit status is 2. (Note: POSIX error handling code should check for '2' or greater.)