On 7/2/24 09:12, Josh Marshall wrote:
> There have been a few times over the course of my career where I just want
> to insert some text.  We have all needed this.  Now, do it at line 5 column
> 5.
> 
> I mean sure, you can split that out with `head`, then some `grep`, the
> text, `grep`, then `tail`.  Or if you're lucky you find yourself in a
> situation where `sed` does what you want.

You don't need luck to get sed to do what you want. If it's just "insert a line"
the sed is pretty straightforward:

$ echo -e 'one\ntwo\nthree\nfour' | sed '3i here is the new line'
one
two
here is the new line
three
four

Replace would be "c" (cut) instead of "i" (insert) after the line number, delete
is "d" with no new text after it.

For columns you probably want the extended regex repeat syntax, "^.{37}" means
must start at left edge, then 37 of any character (because . is regex single
character wildcard), so:

Columns are tricksier, given a $LINE $COLUMN $TEXT and $FILE, something like
this could get stuffed in a shell function:

  sed -iE "$LINEs@^.{$COLUMN}@&$TEXT@" $FILE

Modulo @ occuring in $TEXT, of course. The -i says "edit $FILE in-place" and the
-E says to use extended regex syntax. Slight awkwardness that "0" in columns
means left edge but "1" in lines means first line.

To map to the earlier example:

$ echo -e 'one\ntwo\nthree\nfour' | sed -E "3s@^.{4}@&potato@"
one
two
threpotatoe
four

Although if you're doing a shell function anyway, the relevant bash is probably
something like (untested):

# insert line column "text" < blah > blah
insert() {
  local i x=0
  while read i; do
    [ $((++x)) == "$1" ] && i="${i::$2}$3${i:$2}"
    printf '%s\n' "$i"
  done
}

Of course your proposed command raises design questions about "what if you tell
it to insert off the right edge of the line, or off the end of the file, and is
this unicode columns or ascii columns"...

>  Maybe even `awk`.  But they're
> all painful for what could be just `line:column`.

The existing unix command line has been cryptic for 55 years now, so let's write
a new command is... an argument?

For all I know there is one of these somewhere already, as a standalone command
or option to an existing command (cut, head, fold, fmt, nl, paste, printf,
split, rev, tac, tail, shuf, tee, truncate, xargs...), which I'm not thinking of
because I've never needed it and never seen anyone else need it. Or I did see it
and it was so long ago I've forgotten, and thus wouldn't think to use it in new
scripts...

Rob

Reply via email to