-1

I have a bash loop moving through lines in a file and am wondering if there is a way to interactively replace each line with content.

while read p
do
    echo $p
    read input
    if [ "$input" == "y" ]; then
        # DO SOME ON P REPLACEMENT HERE
done<$fname

From read(3), I know that read copies from the file descriptor into a *buffer. I realize that I can use sed substitution directly but cannot get it to work in this bash loop context. For example, say I want to wrap selected lines:

sed 's/\(.*\)/wrap \(\1\)/'

Complication : The bash 'read' command swallows up '\' and continues reading a 'line' (this is what i'm looking for). Sed seems to NOT. This means that line counts will be different, so a naive counter seems not the way to go if it's to work with sed.

djh
  • 401
  • 1
  • 5
  • 15

2 Answers2

1

Use ex, which is a non-visual mode of vim (it's like a newer ed):

ex -c '%s/\(.*\)/wrap \(\1\)/c' FILE

Note that I needed to add % (do the operation for all lines) and c (prompt before substitution) at the beginning and end of your sed expression, respectively.

When prompted, input y<CR> to substitute, n<CR> to not substitute, q<CR> to stop the substitute command. After inputting q<CR> or reaching the end of file you can save changes with w<CR> (that will overwrite the file) and quit with q<CR>.

Alternatively, you can use ed, but I won't help you with that. ;)

For more general information about ex, check out this question:

https://superuser.com/questions/22455/vim-what-is-the-ex-mode-for-batch-processing-for

Community
  • 1
  • 1
werkritter
  • 1,479
  • 10
  • 12
0

I'm not sure I understand what you need and maybe you can give us more details like a sample input and an expected output. Maybe this is helpful?

while read p
do
    echo "$p"
    read input
    if [ "$input" == "y" ]
    then
        # Sed is fed with "p" and then it replaces any input with a given string.
        # In this case "wrap <matched_text>". Its output is then assigned again to "p"
        p="$(sed -nre 's/(.*)/wrap \1/p' <<< "$p")"
    fi
done < "$fname"
ColOfAbRiX
  • 1,039
  • 1
  • 13
  • 27
  • I might be missing the boat here. This will just print the new p, augmented by sed. Right? I am looking to write back to the file. Probably with a bunch of expensive, looped system calls...but, nonetheless. – djh Jul 09 '15 at 12:46
  • As I said I wasn't sure I understood the question. Bash can't write on a file that's open for read: https://stackoverflow.com/questions/6696842/bash-redirect-input-from-file-back-into-same-file You can then write the modified "p", and everything you need, in a different file and then rename it. For simple replacements you can use only sed, without a bash script http://www.refining-linux.org/archives/27/20-Multi-line-sed-search-and-replace/ – ColOfAbRiX Jul 09 '15 at 12:57
  • 1
    @dagan: The usual trick is to generate a second file based on the content of the file you're reading. Then if everything's successful simply `mv` it to replace the original file. – slebetman Jul 09 '15 at 13:11