0

I need to print all my database configuration, my project uses laravel and CI framework. So in shorts I'm looking for following file.

  • .env → located at /var/www/example_system/.env
  • database.php → located at /var/www/example_system/application/config/database.php
  • core_db.php → located at /var/www/example_system/app/core/core_db.php

I'm using following find command to perform this task.

find /var/www -maxdepth 4 -type f -name ".env" -not \( -path "/var/www/*/config" -prune \) -o -path '*core/*' -name "core_db.php" -o -path '*config/*' -name "database.php"

Which print.

/var/www/baloon/app/core/core_db.php
/var/www/infinys/application/config/database.php
/var/www/duffyweb/.env
/var/www/duffyweb/config/database.php
/var/www/loseweb/.env
/var/www/loseweb/config/database.php
/var/www/resto_app/application/config/database.php

This however fails to meet my need, as it still outputting both

  • /var/www/duffyweb/config/database.php
  • /var/www/loseweb/config/database.php

even though (I thought) I already explicitly exclude it on my find command using -name ".env" -not \( -path "/var/www/*/config" -prune \) parameter.

So my question is How can I exclude something from find, if a directory has specific file in it. In this case if there was .env file, I want find to exclude config/database.php as I prioritize .env over database.php

Liso
  • 188
  • 2
  • 14
  • 1
    `not` and `prune` are a double-negation. Are you sure it is what you want? Side note: as you know already about where the files are, why don't you simply use globbing? For instance `/var/www/*/.env /var/www/*/application/config/database.php /var/www/*/app/core/core_db.php`? If `example_system` can represent more than one hierarchy level you can enable the `globstar` bash option (`shopt -s globstar`) and replace `*` by `**` in the glob patterns. – Renaud Pacalet Dec 03 '21 at 07:54
  • You shouldn't use ***path*** and ***name*** together. Maybe you want something like this: `-not -path '*/core/*.php' -not -path '*/config/*.php'` – Darkman Dec 03 '21 at 08:19
  • @RenaudPacalet I was following this [answer](https://stackoverflow.com/a/16595367/12289283), and yeah the actual situation would be looking for that file in 20+ project in /var/www, each of them has at least `.env` and `config` in 1 project, I'm trying to exclude config one if a project has `.env` file. – Liso Dec 03 '21 at 08:22
  • @Darkman Thank you but I'd like to retain all other result (which has no `.env` in their directory), your method halt that possibility. – Liso Dec 03 '21 at 08:33

1 Answers1

1

Let's assume example_system represents only one hierarchy level and you always want to print core_db.php if the file exists.

The following, rather complex, find command is probably not far:

find /var/www -maxdepth 4 -type f \( \
  -name .env -o -name core_db.php -o \
  -name database.php -exec sh -c '! [ -f "$(dirname "$1")"/../.env ]' _ "{}" \; \
  \) -print

The idea is to add a condition for database.php files with the -exec action. The action is a call to a sub-shell that will return true only if a file named .env does not exist two hierarchy levels under the database.php file. The sub-shell script is rather simple:

! [ -f "$(dirname "$1")"/../.env ]

It takes one argument: the path of the database.php file. It is not called directly as the -exec parameter. Instead, it is called as the script parameter of sh -c:

sh -c 'script' argv0 argv1...

argv0 corresponds to the $0 parameter of the script (unused, thus the _which I frequently use as don't-care) and argv1 corresponds to the $1 positional parameter.

But as it is a bit complex, a more straightforward bash loop may be easier to understand and maintain:

for d in var/www/*/; do 
  e="${d}.env"
  db="${d}application/config/database.php"
  c="${d}app/core/core_db.php"
  if [ -f "$e" ]; then
    echo "$e"
  elif [ -f "$db" ]; then
    echo "$db"
  fi
  if [ -f "$c" ]; then
    echo "$c"
  fi
done
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
  • Thanks ! This actually works. Can you do me a favor of explaining the `-exec` parameter ? Why is there underscore ? – Liso Dec 03 '21 at 09:48
  • I added an explanation. – Renaud Pacalet Dec 03 '21 at 09:55
  • Thanks for your help, much appreciated. – Liso Dec 03 '21 at 09:59
  • Hello, I want to ask minor question. In the `[ -f ]` section, is it possible to test more than 1 match ? My directory for example has `app/core/core_db.php` and `jbapp/core/core_db.php` `applv/core/core_db.php`, the directory structure remain the same but `app` has several variation. I tried to use wildcard to match all name with `app` in it, but it's not working (no output). – Liso Dec 05 '21 at 05:35
  • Do I need to hardcore each directory name onto the for loop ? – Liso Dec 05 '21 at 05:36
  • You would need a nested for loop. Replace `c="${d}app/core/core_db.php"` and `if [ -f "$c" ]; then echo "$c"; fi`by: `for a in "${d}"*app*/; do c="${a}core/core_db.php"; if [ -f "$c" ]; then echo "$c"; fi; done`. – Renaud Pacalet Dec 05 '21 at 06:43
  • Alternately you can use the `find` solution that will print all `core_db.php` files. – Renaud Pacalet Dec 05 '21 at 06:45
  • That works, but it also match `application`, so I get double output for `application/config/database.php`. Is there anyway to exclude it ? Otherwise it's all good – Liso Dec 05 '21 at 08:29
  • You mean `c="${a}core/core_db.php"` also matches `application/config/database.php`? I don't understand how this could be possible. – Renaud Pacalet Dec 05 '21 at 08:54
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/239834/discussion-between-liso-and-renaud-pacalet). – Liso Dec 05 '21 at 08:55