Sed Scripting for beginners - sed

I have two commands I'd like to place in a sed script (to add some headings to a text file that's already been created). The two commands are as follows:
sed '/TEST/i\"-TEST-"\' grades.txt
sed '/PROJECT/i\"-PROJECT-"\' grades.txt
The problem I'm running into is creating the actual script. I start by typing sed -f nameofscript.sed at the command line. From there I type in an opening comment using #, hit enter, then type in my commands (without the grades.txt at the end). Every command I type is echo'd back to me. When I'm finished I again type sed -f nameofscript.sed grades.txt. Nothing seems to end the script. so I hit control-d. When I go to review the script (cat nameofscript.sed) there's nothing there. I've been at this for quite a while so any help would be appreciated. Thank you so much.

You use a text editor to create a script file and then sed -f nameofscript.sed to execute that file.
sed -f does not start an interactive editor.
It runs sed over standard input (which is why it echos your lines back at you since it prints by default and you haven't given it any sed script to execute).
If nameofscript.sed didn't exist then sed -f nameofscript.sed would give you an error message about that when you tried to run it.
To be more explicit, when you run sed -f some_empty_file.sed you are telling sed to run an empty script over standard input. There is no standard input so sed waits and listens for input from your (via the keyboard). When you type into that "dead air" you are feeding sed content lines. It then processes those through its script (which is empty) and executes the default print action and spits them back out at you.

Related

Replace string with $ from makefile with sed

I am trying to replace ${dbPassword} in a property file with a password including $ signs.
My command is the following, but I have no idea how to replace this properly.
run: #cat $(FILE_PATH) | sed -i .bak 's/$${dbPassword}/$(VARIABLE_WITH_PWD)/g' $(FILE_PATH)
Let's say my dbPassword is: 123$456$789
With this, I am getting the result: 123${dbPassword}456${dbPassword}789
Three problems:
Target and recipe on the same line. The recipe must be on the next line, indented with a hard tab.
You pass $(FILE_PATH) on stdin, and as a file argument to sed. Remove the cat pipe.
Shell variables (as opposed to make variables) are not substituted inside single quotes.
So you might want to try this instead:
.PHONY: run
run:
sed -i .bak "s/$${dbPassword}/$(VARIABLE_WITH_PWD)/g" $(FILE_PATH)
This assumes you have an environment variable, dbPassword and exported it prior to running make. If that is not the case, please provide your complete makefile.
I also have removed the # so you actually see what command make is executing. There's no point in wearing a blindfold while debugging your makefile.

What is the significance of -n parameter passed to sed command?

Can someone please tell me how does sed -n '1!p work ? Below is the full command which I am using to sort my pods in k8s based on nodes they are assigned.
kubectl get pods -o wide --all-namespaces|sort -k8 -r| sed -n '1!p'
The above command works perfectly and the sed part removes the first header line from the final output.
I want to understand how does the sed part work and what's the significance of the parameters passed to sed?
From info sed:
-n:
By default, 'sed' prints out the pattern space at the end of each
cycle through the script (*note How 'sed' works: Execution Cycle.).
These options disable this automatic printing, and 'sed' only
produces output when explicitly told to via the 'p' command.
1p: print first line
1!p: do not print first line.
By default, sed will output every line it parses.
-n option is there to hide this output, and display only the lines specified with the p option.
In your exemple, sed -n '1!p' means "Display every line but first".
A more understandable example is when you want to search/replace with sed. If you want to see the whole resulting file you'll use this:
sed 's/from/to/g' file.txt
But if you only want to see which lines have been changed, use this:
sed -n 's/from/to/gp' file.txt

Why does "sed -n -i" delete existing file contents?

Running Fedora 25 server edition. sed --version gives me sed (GNU sed) 4.2.2 along with the usual copyright and contact info. I've create a text file sudo vi ./potential_sed_bug. Vi shows the contents of this file (with :set list enabled) as:
don't$
delete$
me$
please$
I then run the following command:
sudo sed -n -i.bak /please/a\testing ./potential_sed_bug
Before we discuss the results; here is what the sed man page says:
-n, --quiet, --silent
suppress automatic printing of pattern space
and
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if extension supplied). The default operation mode is to break symbolic and hard links. This can be changed with --follow-symlinks and --copy.
I've also looked other sed command references to learn how to append with sed. Based on my understanding from the research I've done; the resulting file content should be:
don't
delete
me
please
testing
However, running sudo cat ./potential_sed_bug gives me the following output:
testing
In light of this discrepancy, is my understanding of the command I ran incorrect or is there a bug with sed/the environment?
tl;dr
Don't use -n with -i: unless you use explicit output commands in your sed script, nothing will be written to your file.
Using -i produces no stdout (terminal) output, so there's nothing extra you need to do to make your command quiet.
By default, sed automatically prints the (possibly modified) input lines to whatever its output target is, whether implied or explicitly specified: by default, to stdout (the terminal, unless redirected); with -i, to a temporary file that ultimately replaces the input file.
In both cases, -n suppresses this automatic printing, so that - unless you use explicit output functions such as p or, in your case, a - nothing gets printed to stdout / written to the temporary file.
Note that the automatic printing applies to the so-called pattern space, which is where the (possibly modified) input is held; explicit output functions such as p, a, i and c do not print to the pattern space (for potential subsequent modification), they print directly to the target stream / file, which is why a\testing was able to produce output, despite the use of -n.
Note that with -i, sed's implicit printing / explicit output commands only print to the temporary file, and not also to stdout, so a command using -i is invariably quiet with respect to stdout (terminal) output - there's nothing extra you need to do.
To give a concrete example (GNU sed syntax).
Since the use of -i is incidental to the question, I've omitted it for simplicity. Note that -i prints to a temporary file first, which, on completion, replaces the original. This comes with pitfalls, notably the potential destruction of symlinks; see the lower half of this answer of mine.
# Print input (by default), and append literal 'testing' after
# lines that contain 'please'.
$ sed '/please/ a testing' <<<$'yes\nplease\nmore'
yes
please
testing
more
# Adding `-n` suppresses the default printing, so only `testing` is printed.
# Note that the sequence of processing is exactly the same as without `-n`:
# If and when a line with 'please' is found, 'testing' is appended *at that time*.
$ sed -n '/please/ a testing' <<<$'yes\nplease\nmore'
testing
# Adding an unconditional `p` (print) call undoes the effect of `-n`.
$ sed -n 'p; /please/ a testing' <<<$'yes\nplease\nmore'
yes
please
testing
more

Makefile $shell into variable sed expanded incorrectly?

I'm having an issue trying to capture the output of a sed command in a makefile variable.
JS_SRC:=$(shell sed -n 's#.*src="\([^"]*\.js\).*#\1#p' index.html)
Which gives me
sed: -e expression #1, char 34: unknown option tos'
`
I've been trying to escape things and the like, but am always given that error.
All variations of escaping I have run, run fine from the terminal.
How does a makefile call the shell command?. /usr/bin/sh -c "cmd?" or something different?.
Somethings being interpolated but I have no idea what.
JS_SRC:=$(shell sed -n "s/.*src=\"\\([^\"]*\\.js\\).*/\\1/p" index.html)
Appears to work. I figured this out via running make -d and seeing the process it was creating.
What was baffling is that it did different things with ' vs " in the sed argument. " is run with /bin/sh -c "args" so I was able to tweak the escaping to get what I needed to appear there. Using ' seems to invoke sed directly.
There is a whole heap of escaping, that i imagine is unnecessary (I don't need to interpolate variables in the sed expression, but it sends it to a shell I understand. So it will have to do ! :)

Execute sed command inside TCL script

I am trying to execute sed command inside TCL script . Basically i wanted to remove all empty lines from the input file before reading the file using TCL. so i tried following in my script
exec sed -i '/^\s*$/d' .tmp.PG_Ring
set fid [open ".tmp.PG_Ring" r]
But the script is dumping following Error .
sed: -e expression #1, char 1: unknown command: `''
while executing
"exec sed -i '/^\s*$/d' .tmp.PG_Ring"
(file "pg_ring.tcl" line 1)
could you please provide me work around for this & help me with best way to do this?
That won't work, as single quotes have no special meaning to Tcl at all. Tcl uses braces to mean the same sort of thing (except they nest nicely), so instead you can use this:.
exec sed -i {/^\s*$/d} .tmp.PG_Ring