0

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?

Cyrus
  • 84,225
  • 14
  • 89
  • 153
Devil's Dream
  • 655
  • 3
  • 15
  • 38
  • Your code has trivial syntax errors. Please try http://shellcheck.net/ before requesting human assistance. See also https://stackoverflow.com/questions/4651437/how-do-i-set-a-variable-to-the-output-of-a-command-in-bash – tripleee Jul 18 '21 at 07:03
  • Please note: [Why *not* parse `ls`?](http://unix.stackexchange.com/questions/128985/why-not-parse-ls) – Cyrus Jul 18 '21 at 07:14
  • 1
    The error message is not consistent with the code you posted. You would get that error if the variable was empty, out you set it to `ls`. – tripleee Jul 18 '21 at 07:29

2 Answers2

0

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 
Walter A
  • 19,067
  • 2
  • 23
  • 43
-1

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.

Tim Roberts
  • 48,973
  • 4
  • 21
  • 30
  • The [`ls` is still useless.](http://www.iki.fi/era/unix/award.html#ls) – tripleee Jul 18 '21 at 07:26
  • @tripleee That's not actually true. `xxx=/opt/files/no.such.file` will produce a string. `xxx=$(ls /opt/files/no.such.file)` will produce an empty string. – Tim Roberts Jul 18 '21 at 18:37
  • But `[ /opt/files/conf.* -eq "/opt/files/conf.json" ]` will be true only when only that file exists. (There will be an unsightly syntax error when the wildcard matches more than one file, though.) – tripleee Jul 18 '21 at 19:49