10

I have this cat then sed operation:

cat ${location_x}/file_1 > ${location_y}/file2
sed -i "s/0/1/g" /${location_y}/file2

Can this be done in a single line?

I might miss such a way here, but that explanation seems to me to deal with the opposite of that, and I fail too unite the above cat and sed into one operation without double ampersand (&&) or semicolon (;) and getting closer to assume it's not possible, but it's important for me to ask here because I might be wrong.

Not all readers are English speakers are familiar with the terms "ampersand" or "semicolon" so I elaborated on these.

2 Answers2

22

Yes:

sed 's/0/1/g' "$location_x/file_1" >"$location_y/file2"

Your code first makes a copy of the first file and then changes the copy using inline editing with sed -i. The code above reads from the original file, does the changes, and writes the result to the new file. There is no need for cat here.

If you're using GNU sed and if the $location_x could contain a leading -, you will need to make sure that the path is not interpreted as a command line flag:

sed -e 's/0/1/g' -- "$location_x/file_1" >"$location_y/file2"

The double dash marks the end of command line options. The alternative is to use < to redirect the contents of the file into sed. Other sed implementation (BSD sed) stops parsing the command line for options at the first non-option argument whereas GNU sed (like some other GNU software) rearranges the command line in its parsing of it.

For this particular editing operation (changing all zeros to ones), the following will also work:

tr '0' '1' <"$location_x/file_1" >"$location_y/file2"

Note that tr always reads from standard input, hence the < to redirect the input from the original file.


I notice that on your sed command line, you try to access /${location_y}/file2, which is different from the path on the line above it (the / at the start of the path). This may be a typo.

Kusalananda
  • 333,661
  • @Kusalananda I didn't understand this text at all If you're using GNU sed and if the $location_x could contain a leading -, you will need to make sure that the path is not interpreted as a command line flag:. What do you mean when $location_x could contain a leading -? Why would someone write - $location_x when it's not part of a command? – Arcticooling Feb 06 '18 at 08:49
  • 1
    @user9303970 I added that bit aftor Stéphane commented, and it's only needed to protect the command in the case where $location_x starts with - (as in -mydir/somewhere). If you can guarantee that $x_location does not start with -, then you may disregard that whole discussion. – Kusalananda Feb 06 '18 at 08:51
  • 1
    @user9303970 It's good practice to be cautious when using user-supplied data in variables, but not needed if you have full control over the contents of those variables and know for sure that it won't cause an issue. – Kusalananda Feb 06 '18 at 08:54
  • @Kusalananda for the actual case I cope with I did: sed "s/\${domain}/${1}/g" "~/myAddons/nginx_app" > "${s_a}/${domain}.conf". I read your answer at least 3 times and I understand that my code is good, but I'm still curious to know how can it be that the sed makes the change (where?), thus making the new redirected file to be created per that change. I am amazed of "how the Bash interpreter processes the command so sophisticated that the sed makes the new redirected file to be created with its own change. intuitively I'd assume "the sed should come in the end, not in the start". – Arcticooling Feb 06 '18 at 09:17
  • @user9303970 But sed comes in the end (it's the only command). It will read from the given file, do its thing, and output the result. The shell handles the plumbing (the redirection to the output file). Your initial second command is the same; it calls sed on a file, does the editing of it and outputs the result. The only difference is that by using -i, sed outputs the result to the same file that it was reading from. – Kusalananda Feb 06 '18 at 09:43
  • Oh, I thought the ${x} > ${y} is a command by itself. I think I miss only this --- where does sed does the change? I mean, I don't want to change the original file, but sed changes content already in it, so if the file isn't changed, I miss where sed makes that change. – Arcticooling Feb 06 '18 at 10:02
  • @user9303970 I'm not quite sure I understand. sed reads from a file and produces changed output. That output is written to another file. If you want to see where the changes happened, you would have to compare the files, either by eye or by using something like diff (which shows the differences between two files). $x >$y is a command, it invokes whatever $x is and redirects the output of that to whatever $y is. The $x command however just do "output", and it's the shell that makes sure that this output goes into $y. – Kusalananda Feb 06 '18 at 10:08
  • I mean: If sed doesn't change file A itself, but still changes something that you could find inside file A, where does sed stores the changed content, before it sends it to file B? – Arcticooling Feb 06 '18 at 10:17
  • @user9303970 sed reads a single line from its input, applies its changes to that single line, and then outputs it. It then reads the next line. Technically, when you use sed -i, the output goes to a new temporary file that is later replacing the original file. With sed (no -i) the shell receives a stream of data (individual lines) from sed and redirects them to a file on disk. If you don't use a redirection (drop everything after > including the > itself), the shell sends the data to your terminal. – Kusalananda Feb 06 '18 at 10:21
  • @user9303970 All of this is fairly basic knowledge and can be picked up from any text or tutorial describing how redirections and commands in general work in the Unix shell environment. I'm not saying this as a way of discrediting your question(s), but we have now gone far beyond the topic of the particular question that you asked. – Kusalananda Feb 06 '18 at 10:23
  • Indeed we went far beyond that. Sorry for that, didn't mean that. I have never seen sed mentioned when I read on redirections in general and the abpve code seemed to me nonintuitive so I asked... – Arcticooling Feb 06 '18 at 10:44
  • @user9303970 No worries. Any command that produces output on its standard output stream may have that output redirected to a file. This includes sed and also tr that I mentioned in my answer. Do ask separate questions on the main site if there are specific things relating to this that you find unclear in the future (after having done your own research into it first). – Kusalananda Feb 06 '18 at 10:47
1

Alternate solution using tee just for a different approach:

cat "${location_x}/file1" |\
  tee "${location_y}/file2" |\
  sed -i "s/0/1/g"

Does the following:

-cat: Reads ${location_x}/file1 and pipes it to tee

-tee: Writes input from cat to ${location_y}/file2 and pipes it to sed

-sed: Runs your sed on the input from tee

Optional: if you want to write the output from sed to a file, just append > /path/to/file to overwrite, or >> /path/to/file to append.

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232