Search code examples
visual-studio-codedevelopment-environment

Is there a way to search for a string in only those files where a previous search found a different string?


I can't manage to find a way to make special edition, e.g., changing a string 'ABC' with a text 'TEXT1 TEXT2' in only files that already met a search criteria that I want.

Example: in all the files that contain the string '-FI-' replace the string 'ABC' with the string 'TEXT1 TEXT2'.

Is there a way/feature to do it please?, I have VScode 1.37.1 installed on Windows10. I want something that can be run in VScode and in worst case maybe some linux stuff can help ...

I tried for example how to make a search inside a search and edit. And I don't have enough knowledge to do it using regex.

Thank you.


Solution

  • Based on the clarifying comments, I interpret the question to be:

    • How can I replace all instances of "ABC" with "TEXT1 TEXT2" within files that also contain the string "-Fl-", starting at a given directory and recursively considering all files beneath it?

    I would solve this using Cygwin shell commands rather than in VSCode.

    First, let's make a file that contains the names of all the files that contain the string "-Fl-". At a bash shell, use cd to go to the directory of interest, and run:

      $ grep -l -r -- '-Fl-' . > files.txt
    

    Breaking this down:

    • grep searches for text within files.
    • The -l switch prints the file names rather than matching lines.
    • The -r switch searches recursively in subdirectories.
    • The -- switch tells grep that that is the last command line option, so subsequent words should be treated as arguments (i.e., text to search for). This is necessary because our search text begins with - and hence would otherwise be treated as an option.
    • The -Fl- is the text to search for (case sensitive; use the -i option for case insensitive search).
    • The . is the place for grep to search, and means "current directory" (plus all files and subdirectories, recursively, due to -r).
    • The > files.txt part says to write the results to files.txt.

    Before going on, open files.txt in an editor or just cat it to the terminal to verify that it looks reasonable to you:

      $ cat files.txt
    

    Now we need to do search and replace in this list of files. This isn't so easy to do with just stock shell commands, so I've written my own script that I use to do it:

    Save that as a file called "replace-across-files". I normally put such things into $HOME/scripts, also known as ~/scripts, so I will assume you've done the same (make that directory first if necessary).

    Now, go back to the directory that has files.txt and run:

      perl ~/scripts/replace-across-files 'ABC' 'TEXT1 TEXT2' $(cat files.txt)
    

    This will interactively prompt you for each occurrence. Use y (or just Enter) to accept each one individually, Y to accept all in the current file, and ! to make all replacements.

    If you get perl: command not found, then you need to install Cygwin perl first.

    One possible gotcha: if any of the file names contain a space, then this won't work because $(cat files.txt) splits files.txt at whitespace boundaries before putting the contents onto the command line. One way to deal with this is to use xargs instead:

      $ cat files.txt | xargs -d '\n' perl ~/scripts/replace-across-files -f 'ABC' 'TEXT1 TEXT2'
    

    Breaking this down:

    • cat files.txt | feeds the contents of files.txt to the next command, xargs, as its input.
    • xargs adds its input onto the given command line and runs it.
    • -d '\n' tells xargs to divide its input at newline boundaries, not any whitespace.
    • -f tells replace-across-files to do all replacements non-interactively. This is necessary because, due to the way xargs works, prompting for each replacement would not work.