-4

A specific file ("target_file") needs editing, if present at depth +2, that is to say if present in any first-level sub-directory with respect to sub-directory path /path/to/alpha/beta.

In other words and for example, the target file of interest can be in sub-dirs:

  • /path/to/alpha/beta/gama/
  • /path/to/alpha/beta/teta/

but not in sub-dir:

  • /path/to/alpha/beta/teta/delta/

The editing consists in substituting a string, perhaps with vim. The string edition consists in incrementing a numeral. For example: 15.47.9001 -> 15.47.9002

How do I do this in Bash?

5
  • your post makes no sense ... gama is a subdirectory ... why would it return true – jsotola Jun 19 '20 at 17:34
  • Directories are relative. pwd -P would tell you that you are somewhere like /home/xuser/bin/alpha/beta/gama. But only you know that alpha is the level you want to count from. And if alpha/theta/phi is true or false. – Paul_Pedant Jun 19 '20 at 18:16
  • @jsotola I want to return true only if I'm in any of the first level subdirectories. If I'm in the exact path or more level downs I want to return False. – user3541631 Jun 21 '20 at 10:01
  • It is now too broad. But maybe a find -type f -name "$target_file|grep -v ^"$excl_subdir"|xargs vim would likely do some similar what you want to. – peterh Jun 25 '20 at 9:12
  • 1
    @peterh: How is it too broadly formulated ? Your suggestion in comment does not filter out by -maxdepth and -path, which are the better way to find a file to be edited, at a certain sub-dir level, in an otherwise unpredictable sub-directory tree. – Cbhihe Jun 25 '20 at 10:06
0

[This was tested on bash 5.0.17 with find 4.7.0 (Gnu findutils) and sed 4.7 (Gnu).]

  • target_file: can be a regexp pattern; cannot contain /.
  • D: depth of searched target_file relative to where your search path points, 1 for the current directory level specified as ./, 2 for 1st level subdirectory, for instance ./foobar/.
  • use a pattern for the example string 15.47.9001 (as provided), which is to be replaced by 15.47.9002.

So, for instance, if /path/to/alpha/beta were 4 sub-directories levels, you would use D=6.

$ find /path/to/alpha/beta/ \
-maxdepth D \
-type f \
-name "target_file" 2>/dev/null \
-exec sed -i 's/\([0-9][0-9]\.[0-9][0-9]\.\)\([0-9][0-9][0-9][0-9]\)/printf "%s%04d" "\1" "$((1\2-9999))"/e' {} \;

Notes:

  • finds the sought regular file, if it exists, along specified paths and at the specified max depth according to target_file name pattern.
  • in place substitution (-i) of regex pattern space [0-9][0-9].[0-9][0-9].[0-9][0-9][0-9][0-9] by printf "%s%04d" "\1" "$((1\2-9999))" where \1 represents pattern space sub-string [0-9][0-9].[0-9][0-9]. and \2 represents pattern space sub-string [0-9][0-9][0-9][0-9].
  • above pattern space sub-strings are delimited by \(...\).
  • perform the arithmetic operation $((1\2-9999)) on sub-string \2.
  • the sed 's/.../shell cmd .../e' input_file construct permits piping the result of a shell command into pattern name space as sed executes the substitution. It is specific to GNU sed.
  • depending on your path /path/to/alpha/beta/ you may want to redirect "Permission denied" errors with 2>/dev/null or carefully run the one liner with sudo after checking that find's hits are good.
  • in case you don't know the absolute path /path/to/alpha/beta/ a priori, automating the string substitution remains possible at the cost of a bit more scripting and with appropriate tests on the paths that lead to hits on target_file... maybe for a separate question, since you did not ask for this here.

Edit: Thank you to @G-ManSays'Reinstate Monica' for suggested improvements, in particular but not only where the arithmetics operation is concerned.

5
  • I have a path. In the path I have multiple sub-directories. In any of the first-level subdirectories I can have this file. The number of subdirectories, and their exact name is not predefined. After I modify this file I execute a command in that subdirectory. – user3541631 Jun 21 '20 at 10:02
  • 1
    is a text file, (manually I open with vim). I'm searching for a pattern (a number) and increase that number by one. For example 15.47.9001 -> 15.47.9002 – user3541631 Jun 23 '20 at 16:16
  • I believe that the question is so unclear that it should be closed.  Having said that, (1) +1 for using -maxdepth.  (2) Given the requirement to find files under /path/to/alpha/beta, it seems like you should do find /path/to/alpha/beta … rather than find / -path "/path/to/alpha/beta/*" …, which might search the entire filesystem (depending on how smart find is).  (3) Your command uses sed -E and \(…\).  Actually, you should either use -E and then use (…) for capture groups, or use \(…\) and omit -E.  … (Cont’d) – G-Man Says 'Reinstate Monica' Jul 14 '20 at 7:37
  • 1
    (Cont’d) …  (4) You might want to be just a little more emphatic about the fact that sed’s s/…/…/e construct is a GNU extension and is not available in all versions of sed.  (5) You have an extra set of parentheses: $((…)) is enough; you don’t need $(((…))).  (6) Your edit (numeric increment) command fails if the third component of the number (the four-digit number after the second .) is less than 1000.  For example,  … (Cont’d) – G-Man Says 'Reinstate Monica' Jul 14 '20 at 7:37
  • 1
    (Cont’d) …  it substitutes 15.47.0000 → 15.47.1, 15.47.0001 → 15.47.2, 15.47.0007 → 15.47.8, 15.47.0010 → 15.47.9 (!), 15.47.0100 → 15.47.65, 15.47.0777 → 15.47.512, and fails altogether for values like 0008, 0009, 0778, 0999, and others.  A RHS of printf "%s%04d" "\1" "$((1\2-9999))" seems to work.  Or use printf "%s%04d" "\1" "$((10#\2+1))". (These do substitute 15.47.9999 → 15.47.10000, which seems non-ideal; as I said, the question isn’t clear about how to handle that.) – G-Man Says 'Reinstate Monica' Jul 14 '20 at 7:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.