简体   繁体   中英

How to input a command's result as a string argument in sed

i want to execute a command as follows on my bash terminal:

sed -i '6i `sed '1!d' input.in`' out

with which i can insert at line 6 of file out (with replacing -i option) the result of the sed '%1!d' input.in command. I haven't found anything useful, and have tried both `com`, $(com) and com | sed -i '6i ' out, where com stands for sed '%1!d' input.in . I don't have any problem changing the syntax of the whole command but i want it to be written in one line on terminal use sed.

Thanks for listening, awaiting your answer.

For EdMorton:

Example Input:

input.in:
into a lake.

out:
Mary was runing around a pond and fell
into a lake.


Mary fell into a what?

Desired Output:
Mary was runing around a pond and fell
into a lake.


Mary fell into a what?
into a lake.

Try using r on standard input instead of i .

sed '%1!d' input.in |
sed -i '6r /dev/stdin' out

If your platform doesn't support /dev/stdin or /dev/fd/0 , see if your sed supports - to mean standard input ... or, in the worst case, resort to a temporary file.

As commenters have already pointed out, %1!d does not appear to be a valid command in most sed dialects, but that is basically unimportant here. (If you mean to print just the first line, maybe you mean sed '1!d' , although sed 'p;q' does that more efficiently.)

sed is for simple substitutions on individual lines, that is all. For anything else you should be using awk.

Given this modified input file

$ cat input.in
a Windows folder C:\Windows\Temp

Here is what the sed solution you posted in your comments does:

$ sed '1!d' input.in > temp.of.in && sed "6i `cat temp.of.in`" out
Mary was runing around a pond and fell
into a lake.


Mary fell into a what?
a Windows folder C:WindowsTemp

and here is what an awk solution does more efficiently and accurately and without a temp file:

$ awk 'NR==1{x=$0;nextfile} FNR==6{print x} 1' input.in out
Mary was runing around a pond and fell
into a lake.


Mary fell into a what?
a Windows folder C:\Windows\Temp

Notice the awk solution preserved the path-separator backslashes while the sed one stripped them. Also note that you should really add && rm temp.of.in to the end of your sed command line to clean up the temp file and you should be using $(..) to execute your command, not obsolete backticks.

The awk solution uses GNU awk for ;nextfile , with other awks you'd replace that with }NR==FNR{next or similar but since you are using GNU sed I assume you have GNU awk too.

Note that if you DID have a burning desire to use sed and accept it won't exactly reproduce the input, there are simpler, more efficient ways to do what your current script does, eg:

sed "6i $(head -1 input.in)" out

or even your original idea, just rewritten to remove the obsolete backticks and negative logic of 1!d :

sed "6i $(sed -n '1p' input.in)" out

But seriously - just use awk. For anything other than simple substitutions on individual lines it's much more robust, efficient, clear, portable, extensible, etc. etc. than sed.

EDIT To address the questions in your comments:

  1. Can you explain the arguments on awk. There are no arguments, just a script that says: If this is the first line read from the first file save it in variable x then move on to the next file. If this is line 6 of the 2nd file print the contents of variable x. For every line of the 2nd file, print it (the 1 is idiomatic but a bit tricky at first glance - it's a true condition so it invokes the default action of printing the current input, equivalent to just writing {print} .
  2. how can i replace the out file with the output (without using '>') as the option -i does on sed and avoid printing it to stdout? Just like GNU sed has -i , GNU awk has -i inplace . Be careful though because, just like with sed, it applies to every input file so if you don't print the contents of the first file then when the script is done the first file will be empty. There's various was to deal with that, including simply printing the lines from file 1 or turning inplace editing on/off in BEGINFILE/ENDFILE blocks, see https://www.gnu.org/software/gawk/manual/gawk.html#Extension-Sample-Inplace , but IMHO awk 'script' file1 file2 > temp && mv temp file2 is the simplest and clearest as well as being portable to all awks/seds/whatever.
  3. Also if there is a multiline solution like "take lines 1 to 4" from "input.in" and drop them on line 6 of "out"? No problem:

.

awk '
    NR==FNR { if (NR<=4) x=x $0 ORS; else nextfile }
    FNR==6 { printf "%s", x }
    { print }
' input.in out

I changed the 1 from the previous script to { print } for clarity.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM