What is the function of the '-n option' in sed? [closed] - sed

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 6 months ago.
Improve this question
Can anyone give me an example to showcase the usage of the -n option? The way the document explained it was too vague for me.

Toggles if the line is printed even if no match.
Given these lines:
$ printf '%s\n' {a..c}{0..1}
a0
a1
b0
b1
c0
c1
With -n only prints the lines with a '1' match:
$ printf '%s\n' {a..c}{0..1} | sed -n '/1/p;'
a1
b1
c1
Without -n every line is printed and the lines with '1' match are printed a second time because of the p command:
$ printf '%s\n' {a..c}{0..1} | sed '/1/p;'
a0
a1
a1
b0
b1
b1
c0
c1
c1
Easily available with man sed:
-n By default, each line of input is echoed to the standard output
after all of the commands have been applied to it. The -n option
suppresses this behavior.

You use the -n option when you're using sed as a filter and are mainly eliminating material, so you don't want input lines printed by default. In the absence of -n, at the end of each edit cycle, the 'line' in the pattern space is printed by default. For example:
sed -n -e '/something/ s/another-thing/dohicky/p' some-file
This looks for lines containing 'something', and effectively ignores all other lines. On the lines that match 'something', the string 'another-thing' is replaced by 'dohicky' and the resulting line is printed.
A slightly more realistic example: change the shell of users of csh to tcsh:
sed -n -e '/\bin\csh/ s%/bin/csh%/bin/tcsh%p' /etc/passwd
This shows you only the lines that will be changed. Then, if you decide it is correct, you can use:
sed -i .bak -e '/\bin\csh/ s%/bin/csh%/bin/tcsh%' /etc/passwd
to make the changes permanent. Still not a good example (you need to lock the password file so it is not modified by other programs while you're editing it, and so on and so forth), but it looks more realistic.

Related

Linux shell script, parsing each line [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I am facing a problem with my shell script (I'm using SH):
I have a file with multiple line including mail adressess, for example:
abcd
plm
name_aA.2isurnamec#Text.com -> this is a line that checks the correct condition
random efgh
aaaaaa
naaame_aB.3isurnamec#Text.ro ->same (this is not part of the file)
I have used grep to filter the correct mail adresses like this:
grep -E '^[a-z][a-zA-Z_]*.[0-9][a-zA-Z0-9]+#[A-Z][A-Z0-9]{,12}.(ro|com|eu)$' file.txt
I have to write a shell that cheks the file and prints the following (for the above example it would be like this ):
"Incorrect:" abcd
"Incorrect:" plm
"Correct:" name_aA.2isurnamec#Text.com
"Incorrect:" random efgh
"Incorrect:" aaaaaa
"Correct:" naaame_aB.3isurnamec#Text.ro
I want to solve this problem using grep or sed, while, if, or pipes etc i dont want to use lists or other things.
I have tried using something like this
grep condition abc.txt | while read -r line ; do
echo "Processing $line"
# your code goes here
done
but it only prints the correct lines, and i know that i can also print the lines that dont match the grep condition using -v on grep, but i want to print the lines in the order they appear in the text file.
I'm having trouble trying to parse each line of the file, or maybe i don't need to parse the lines 1
by 1, i really dont know how to solve it.
If you could help me i would appreciate it.
Thanks
#!/bin/bash
pattern='^[a-z][a-zA-Z_]*\.[0-9][a-zA-Z0-9]+#[A-Z][A-Za-z0-9]{,12}\.(ro|com|eu)$'
while read line; do
if [ "$line" ]; then
if echo "$line" | grep -E -q $pattern; then
echo "\"Correct:\" $line"
else
echo "\"Incorrect:\" $line"
fi
fi
done
Invoke like this, assuming the bash script is called filter and the text file, text.txt: ./filter < text.txt.
Note that the full stops in the regular expression are escaped and that the domain name can contain lowercase letters (although, I think that your regex is too restrictive). Other characters are not escaped because the string is in single quotes.
while reads the standard input line by line into $line; the first if skips the empty lines; the second one checks $line against $pattern (-q suppresses grep output).

Keep lines containing "list of different words" like pattern [duplicate]

This question already has answers here:
How to make sed remove lines not matched by a substitution
(4 answers)
Boolean OR in sed regex
(4 answers)
Closed 4 years ago.
How can I keep all lines matching all those words
toto OR titi OR clic OR SOMETHING and delete any other lines?
If I do sed '/toto/ p ' file I cannot select titi for example.
What I am looking for is something similar to a Perl Regular expression as
^ (word1|word2|word3|andsoon).*. However, I need it for sed because it will be integrated into a bigger sed script.
The goal is to keep all lines starting with word where word is any word from a set of words.
The answer here depends a bit on how your master script is called. Imagine you have a file with the following content:
foo
car
bar
and you are interested in the lines matching "foo" and "bar", then you can do:
sed '/foo\|bar/!d'
sed -n '/foo\|bar/!d;p'
sed -n '/foo\|bar/p'
all these will output:
foo
bar
If you would just do:
sed '/foo\|bar/p'
you actually duplicate the lines.
foo
foo
car
bar
bar
As you see, there is a bit of different handling depending on the usage of the -n flag.
-n, --quiet, --silent suppress automatic printing of pattern space
source: man sed
In general, my suggestion is to delete the lines you don't need at the beginning of your sed script.

Create multiple text files from single text file with text found between a repeating identical pattern [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I have a text file of the form:
pattern
info
pattern
different info
pattern
more different info
This repeats 50 times. I'd like to take this file and create 50 files each of which just contains:
pattern
whatever info is below and stoping just before the next header.
To be clear, the pattern is exactly the same all 50 times and then it has unique data below it.
Could someone please tell me how to do this with grep or sed or something?
Thanks
Try:
awk '/pattern/{close(f); f="file" ++c ".out"} f{print>f}' file
This creates files file1.out, file2.out, etc with info starting with pattern.
How it works
/pattern/{close(f); f="file" ++c ".out"}
Every time that we see a line matching regex pattern, close file f and assign a new name to f. c is a counter which is incremented every time that we see pattern.
f{print>f}
If f is nonempty (meaning that we have seen the first occurrence of pattern), then print the current line to file f.
Example
Let's start with this sample file:
$ cat file
pattern
info
pattern
different info
pattern
more different info
Now, let's run our command and look at the output files that it creates:
$ awk '/pattern/{close(f); f="file" ++c ".out"} f{print>f}' file
$ cat file1.out
pattern
info
$ cat file2.out
pattern
different info
$ cat file3.out
pattern
more different info
You can use split
split -l 4 infile

How to use number flags in sed

I have read sed info. In capture 3.5 :The s Command
There is a description:
The s command can be followed by zero or more of the following flags:
number
Only replace the numberth match of the regexp.
Note: the posix standard does not specify what should happen when you mix
the g and number modifiers, and currently there is no widely agreed
upon meaning across sed implementations. For GNU sed, the interaction
is defined to be: ignore matches before the numberth, and then match
and replace all matches from the numberth on.
I do not know how to use it ,who can give a example.
echo a1 | sed -n 's/\(a\)1/\13/p'
the result is no different with
echo a1 | sed -n 's/\(a\)1/\13/1p'
try this:
echo "hi hi hi" | sed 's/hi/hello/2'
echo "hi hi hi" | sed 's/hi/hello/3'
The number obviously only makes sense when there is more than one match.
sed 's/a/b/4' <<<aaaaa
aaaba
If there isn't a fourth match, obviously, no substitution takes place.

Using sed how to remove last character only in the first line [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
How can I use sed to remove the last character from only the first line of a file?
You can for example use this:
sed '1 s/.$//' file
Explanation
1 indicates the line in which we want to perform the action.
given the syntax s/text/replacement/, we look for any character with . followed by $, which indicates end of line. Hence, we look for the last character before end of line and replace it with nothing. That is, we remove the last character of the line.
To edit the file you can use -i.bak.
Test
$ cat a
hello this is some text
and this is something else
$ sed '1 s/.$//' a
hello this is some tex
and this is something else
For fun, let's see how to accomplish this with awk:
awk -v FS= -v OFS= 'NR==1{NF=NF-1}1' file
This sets the input and output field separators (FS, OFS) as empty (same as BEGIN{FS=OFS=""}), so every single character is a field. Based on that, when the record is 1 (in this case, when we are in the 1st line), decrement the number of fields (NF) so that the last character is "lost". Then 1 is a true condition that makes awk perform its default action: {print $0}.