How to check a character value at a position on a line and then add a character at another position on an another line using sed command - shell

Eg. Input Text file
line 1 - Abchsffmskdv
line 2 - bsdvnld
line 3 - fsdgdhdh
If line 1, position 9 is s, then change line 3, position 4 to k
Output:
line 1 - Abchsffmskdv
line 2 - bsdvnld
line 3 - fsdkdhdh

Please try the following:
sed '
/^.\{8\}s/ { # if the 9th char == "s" then
$!n # flush current line and read next line (unless eof)
$!n # same as above to proceed to the line after next
$!s/^\(.\{3\}\)./\1k/ # replace the 4th char with "k"
}' input.txt
or as a one-liner:
sed '/^.\{8\}s/{$!n; $!n; $!s/^\(.\{3\}\)./\1k/}' input.txt
input.txt looks like:
Abchsffmskdv
bsdvnld
fsdgdhdh
iiiiiiiisiii
iiiiiii
iiiiiiii
output:
Abchsffmskdv
bsdvnld
fsdkdhdh
iiiiiiiisiii
iiiiiii
iiikiiii
You'll see the script above replaces the 4th character of the next next
line if the pattern is found regardless of the line number.
If you want to fix the line number to e.g. the 1st line, try instead:
sed '
1 {
/^.\{8\}s/ {
$!n
$!n
$!s/^\(.\{3\}\)./\1k/
}
}' input.txt
output:
Abchsffmskdv
bsdvnld
fsdkdhdh
iiiiiiiisiii
iiiiiii
iiiiiiii
which modifies the 3rd line only.

This might work for you (GNU sed):
sed -E '1h;3{G;s/(...).(.*)\n.{8}s/\1k\2/}' file
Store the first line in the hold space and append it to line 3 and pattern match for the desired criteria.
An alternative:
sed -E '1h;3{x;/^.{8}s/{x;s/./k/4;x};x}' file

Related

Replace Line with Matching Pattern

I have a file filled with two line couplets, a header line that starts with // and ends with the line number surrounded by |, followed by a line of text that is variable in length. Here's an example, where ... indicates that the file continues with sequential line numbers for many lines.
// * * - - - * |1|
textextextextextextextext
// *- *-* * |2|
textextextextextextextexttextextextext
...
// * - * -* |41232|
textextextextextextext
I would like to find the line number, then replace the header line with >linenumber. This example file would be:
>1
textextextextextextextext
>2
textextextextextextextexttextextextext
...
>41232
textextextextextextext
I know this probably involves /s and sed or awk with a backreference, but I'm just can't seem to make it work.
A sed one-liner:
sed 's%^//.*|\([0-9]*\)|$%>\1%' file
Yes, sed is a good tool to do it:
sed -E '\%^//.*\|[[:digit:]]+\|% s/.*\|([[:digit:]]+)\|/>\1/'
Explanation:
\%^//.*\|[[:digit:]]+\|% This is an address, i.e. the following s/// command will only run on matching lines. It matches // at the start of a line, and somewhere later there must be a number between vertical bars.
The substitution replaces the whole line with the captured number.
Using any awk:
$ awk -F'|' 'NF>1{$0=">" $2} 1' file
>1
textextextextextextextext
>2
textextextextextextextexttextextextext
...
>41232
textextextextextextext
The above assumes that text never includes |s.

sed command replace muti line with reg

I got a text like this:
TOKEN = decrypt_aes(
"189272123124aqephkiz3")
And I want to change it into:
TOKEN = "189272123124aqephkiz3"
How can I make this?
I can do this when its in a single line with following command:enter code here`
sed -i "s/decrypt_aes(\(.*\))/\1/g"
But I don`t no how to do when its in multi line
If your file contains only the two lines you showed, then this might help with GNU sed:
sed -i 'N; s/decrypt_aes(\n *//; s/)//' file
From man sed:
N: Append the next line of input into the pattern space.
You can use
sed -i '/.*decrypt_aes($/{N;s/^\([^=]*=\).*\(".*"\))$/\1 \2/}' file
Details:
/.*decrypt_aes($/ - matches a line that ends with decrypt_aes( substring, and if it matches, the block that follows is executed
N - append a newline and the next line to the pattern space
s/^\([^=]*=\).*\(".*"\))$/\1 \2/ - replaces
^\([^=]*=\).*\(".*"\))$ - start of string in the pattern space (^), any zero or more chars other than = and then a = are captured into Group 1 (\1), then any text (.*), then a "..." substring (captured into Group 2 (\2)) and then a ) at the end of string
\1 \2 is the replacement pattern, which is Group 1 value + space + Group 2 value.
See the online demo:
#!/bin/bash
s='TOKEN = decrypt_aes(
"189272123124aqephkiz3")'
sed '/.*decrypt_aes($/{N;s/^\([^=]*=\).*\(".*"\))$/\1 \2/}' <<< "$s"
Output:
TOKEN = "189272123124aqephkiz3"
This might work for you (GNU sed):
sed 'N;s/decrypt_aes.*\(".*"\).*/\1/;P;D' file
Append the following line and if the combined lines matches decrpty_aes followed by "...", replace the match by the string "...".
N.B. If no match is found, each line will be printed as is.

sed insert line after a match only once [duplicate]

UPDATED:
Using sed, how can I insert (NOT SUBSTITUTE) a new line on only the first match of keyword for each file.
Currently I have the following but this inserts for every line containing Matched Keyword and I want it to only insert the New Inserted Line for only the first match found in the file:
sed -ie '/Matched Keyword/ i\New Inserted Line' *.*
For example:
Myfile.txt:
Line 1
Line 2
Line 3
This line contains the Matched Keyword and other stuff
Line 4
This line contains the Matched Keyword and other stuff
Line 6
changed to:
Line 1
Line 2
Line 3
New Inserted Line
This line contains the Matched Keyword and other stuff
Line 4
This line contains the Matched Keyword and other stuff
Line 6
You can sort of do this in GNU sed:
sed '0,/Matched Keyword/s//New Inserted Line\n&/'
But it's not portable. Since portability is good, here it is in awk:
awk '/Matched Keyword/ && !x {print "Text line to insert"; x=1} 1' inputFile
Or, if you want to pass a variable to print:
awk -v "var=$var" '/Matched Keyword/ && !x {print var; x=1} 1' inputFile
These both insert the text line before the first occurrence of the keyword, on a line by itself, per your example.
Remember that with both sed and awk, the matched keyword is a regular expression, not just a keyword.
UPDATE:
Since this question is also tagged bash, here's a simple solution that is pure bash and doesn't required sed:
#!/bin/bash
n=0
while read line; do
if [[ "$line" =~ 'Matched Keyword' && $n = 0 ]]; then
echo "New Inserted Line"
n=1
fi
echo "$line"
done
As it stands, this as a pipe. You can easily wrap it in something that acts on files instead.
If you want one with sed*:
sed '0,/Matched Keyword/s//Matched Keyword\nNew Inserted Line/' myfile.txt
*only works with GNU sed
This might work for you:
sed -i -e '/Matched Keyword/{i\New Inserted Line' -e ':a;n;ba}' file
You're nearly there! Just create a loop to read from the Matched Keyword to the end of the file.
After inserting a line, the remainder of the file can be printed out by:
Introducing a loop place holder :a (here a is an arbitrary name).
Print the current line and fetch the next into the pattern space with the ncommand.
Redirect control back using the ba command which is essentially a goto to the a place holder. The end-of-file condition is naturally taken care of by the n command which terminates any further sed commands if it tries to read passed the end-of-file.
With a little help from bash, a true one liner can be achieved:
sed $'/Matched Keyword/{iNew Inserted Line\n:a;n;ba}' file
Alternative:
sed 'x;/./{x;b};x;/Matched Keyword/h;//iNew Inserted Line' file
This uses the Matched Keyword as a flag in the hold space and once it has been set any processing is curtailed by bailing out immediately.
If you want to append a line after first match only, use AWK instead of SED as below
awk '{print} /Matched Keyword/ && !n {print "New Inserted Line"; n++}' myfile.txt
Output:
Line 1
Line 2
Line 3
This line contains the Matched Keyword and other stuff
New Inserted Line
Line 4
This line contains the Matched Keyword and other stuff
Line 6

Replace k-th to n-th characters in 1st line and last line using bash?

I want to replace some characters in header and footer of a file. If say, I want to replace 5th to 9th character how do I do it? I need to use bash or a shell command.
I want to do something like this
s="abcdabcd"
s=s=s[0]+"12"+s[4:]
>a12dabcd
I have a string of exact length I can substitute and the start and end of replacement. I want to put the generated replacement back into the file.
Example:
I have this header:
HEADER 22aabbccdd23aabbccdd
I get these start and end indices : 2,10
I get this string: xyz56789
I want this: HEADER 22xyz5678923aabbccdd
to replace the existing 1st line in the file.
This can be done with Perl:
perl -i -lpe 'if ($. == 1 || eof) { substr($_, 1, 2) = "12" }' input.txt
-i: modify file in place
-l: automatically strip newlines from input and add them back on output
-p: iterate over lines of the input file and print them back out
-e CODE: what to do for each line
First we check whether the current line number ($.) is 1 (i.e. we're processing the first line of the file) or we have reached the end of the file (i.e. the line currently being processed is the last line of the file). If the condition is true, we take the substring of the current line ($_) starting from offset 1 of length 2 and set it to "12".
Simply with sed:
input.txt:
$ cat input.txt
22aabbccdd23aabbccdd
asasdfsdfd234234234234
$ sed -Ei '1 s/(..).{8}/\1xyz56789/' input.txt
Result:
22xyz5678923aabbccdd
asasdfsdfd234234234234

How to get the first non comment line number in a file?

I have a big file that might have some comments in the header
# Comment line 1
# Comment line 2
# ...
# Comment line ...
# ...
# Comment line N
123
234
345
...
I need a one line solution to get the number "N+1", what's the most elegant way to achieve this using shell script? Thanks
try this sed one-liner:
sed -n '/^\s*#/!{p;q}' file
ok, if you need only the line-number:
sed -n '/^\s*#/!{=;q}' file
add short explanation:
/^\s*#/! : regex, if the line does NOT start with 0 or more empty chars (tab/space)then a '#', the line is chosen for further step.
= : print line no
q : quit processing
awk version:
awk '$1~/^[^#]/{print NR; exit}' file

Resources