Asked  7 Months ago    Answers:  5   Viewed   22 times

I would like to run a find and replace on an HTML file through the command line.

My command looks something like this:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html > index.html

When I run this and look at the file afterward, it is empty. It deleted the contents of my file.

When I run this after restoring the file again:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

The stdout is the contents of the file, and the find and replace has been executed.

Why is this happening?

 Answers

74

When the shell sees > index.html in the command line it opens the file index.html for writing, wiping off all its previous contents.

To fix this you need to pass the -i option to sed to make the changes inline and create a backup of the original file before it does the changes in-place:

sed -i.bak s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

Without the .bak the command will fail on some platforms, such as Mac OSX.

Tuesday, June 1, 2021
 
BradM
answered 7 Months ago
86

Not really what we do here, but I would think you would just change line 17:

if( is_file( $path ) && substr($path, -3)=='php' && substr($path, -17) != 'ChangePHPText.php'){

to

if( is_file( $path ) && substr($path, -4)=='html' && substr($path, -17) != 'ChangePHPText.php'){

Though honestly, if you're doing that much text change, you may find a text editor that does string replacement in files to be much faster.

Wednesday, March 31, 2021
 
Fernando
answered 9 Months ago
49

This error:

ls: *.xyz: No such file or directory

is being written on stderr by ls binary.

However in this command:

ls -al *.xyz 2>&1 1> files.lst

You're first redirecting stderr to stdout which by default goes to tty (terminal)

And then you're redirecting stdout to a file files.lst, however remember that stderr doesn't redirected to file since you have stderr to stdout redirection before stdout to file redirection. Your stderr still gets written to tty in this case.

However in 2nd case you change the order of redirections (first stdout to file and then stderr to stdout) and that rightly redirects stderr to a file which is also being used by stdout.

Thursday, June 3, 2021
 
Anand
answered 6 Months ago
11

Install the Find And Replace Text command line utility and then you can simply enter

fart *.txt E:Test E:TestTemp
Tuesday, November 9, 2021
 
Bart Kiers
answered 3 Weeks ago
27

I think that file should be opened, and dup2 method used, but I don't know in which way

You are right about the mechanisms for implementing the redirection. It should be done on the process intended for tr, and before performing the overlay.


Let's go step by step:

ls | tr a b > text.txt

First create a pipe, then fork().

From now on, there are two processes running in parallel, both of them will be eventually overlaid by means of exec(): one with the ls program, the other with the tr program.

Process for ls:

  1. Close the reading end of the pipe: this process will only write to the pipe.
  2. dup2() the writing end of the pipe to STDOUT: what this process writes to STDOUT is being written to the pipe.
  3. Perform the overlay: exec() with ls.

Process for tr:

  1. Close the writing end of the pipe: this process will only read from the pipe.
  2. dup2() the reading end of the pipe to STDIN: what this process reads from STDIN is coming from the pipe.
  3. In order to perform the redirection to the text.txt file, first open() the file text.txt for writing and with the flags O_CREAT and O_TRUNC, then dup2() the obtained file descriptor to STDOUT.

  4. Perform the overlay: exec() with tr.


Note that, if the command were appending to text.txt instead of truncating it (i.e.: using >> instead of >):

ls | tr a b >> text.txt

You would have to use the flag O_APPEND instead of O_TRUNC when open()ing the text.txt file.


Code Snippet

I've modified your code (also the interface of fork_pipes()). It's a minimal example that runs, I hope it helps.

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int spawn_proc (int in, int out, char** cmd) {
    pid_t pid;

    if ((pid = fork ()) == 0) {
        if (in != 0) {
          dup2 (in, 0);
          close (in);
        }
        if (out != 1) {
          dup2 (out, 1);
          close (out);
        }

      return execvp (cmd[0], cmd);
    }

    return pid;
}

void fork_pipes (char** cmd[], const char *redirection) {
  int i, n;
  int in, out, fd[2];

  in = 0;

  // obtain n from the NULL terminated cmd array
  for (n = 0; cmd[n]; ++n)
    ;

  // process all but the last elemet of the pipe
    for (i = 0; i < n-1; ++i) {
        pipe(fd);
        spawn_proc(in, fd[1], cmd[i]);
        close(fd [1]);
        in = fd [0];
  }

  // process the last element of the pipe
    if (redirection) {
        out = open(redirection, O_WRONLY | O_CREAT | O_TRUNC);
        fchmod(out, 0666);
    } else
        out = STDOUT_FILENO;

    if (in != 0)
        dup2(in, 0);

    spawn_proc(in, out, cmd[i]);
}

int main()
{

    char *cmd1[] = {"ls", NULL};
    char *cmd2[] = {"tr", "a", "b", NULL};
    char **cmd[] = { cmd1, cmd2, NULL};

    // redirected to text.txt
    fork_pipes(cmd, "text.txt");

    // no redirection
    fork_pipes(cmd, NULL);

    // another example with a longer pipe 
    {
        char *cmd1[] = {"echo", "hello world", NULL};
        char *cmd2[] = {"tee", NULL};
        char *cmd3[] = {"tee", NULL};
        char *cmd4[] = {"tr", "lo", "10", NULL};

        char **cmd[] = {cmd1, cmd2, cmd3, cmd4, NULL};

        // redirected to redirection.txt
        fork_pipes(cmd, "redirection.txt");

        // no redirected
        fork_pipes(cmd, NULL);
    }

    return 0;
}

As already pointed out in this comment. You just need to call pipe() once in your example: The pipe() system call only needs to be called once for each pipe operator (i.e.: the | character) found in the compound command. For example, in the following command:

cmd1 | cmd2 | cmd3 | cmd4

pipe() must be called exactly four times, since there are four pipe operators.

Friday, November 26, 2021
 
Cavyn VonDeylen
answered 6 Days ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share