Add blank line before a certain phrase in a text file in Linux? - linux

I'm using Kali Linux, trying to sort out some input from Nmap. Basically, I ran a scan from NMap, and need to extract specific pieces of information from it. I've got it to show everything I need using the following command:
cat discovery.txt | grep 'Nmap scan report for\|Service Info: OS:\|OS CPE:\|OS guesses:\|OS matches\|OS details'
Essentially, each section of information I need will start with "Nmap scan report for [IP ADDRESS]"
I'd like to add to my command to have it create a blank line before every appearance of the word "Nmap", to clearly separate each chunk of information.
Is there any command I can use to do this?

sed '/Nmap/i
' file
That's a literal newline after the i
A demo: add a newline before each line ending with a "0" or a "5"
seq 19 | sed '/0$\|5$/i
'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Sure, you can use Perl.
perl -pe 's/^Nmap/\nNmap/'

Related

What does this SED command do and how can I modify it for my use case?

I have been asked to fix someone else code so im unsure how the command actually works as ive never had to work with regex type code.
sed -r 's/([0-9]{2})\/([0-9]{2})\/([0-9]{4})\s([0-9]{2}:[0-9]{2}:[0-9]{2})/\3\/\1\/\2 \4/g'
This code reads the below txt file and is 'meant' to display the number in bold below.
placeholder_name 01/01/2022 12:00:00 01/01/2022 12:00:01 STATUS 12345/15 50
This is output to a new temp file but the issue is that only the first character in the number after the '/' is displayed, i.e. for the above example only 1 is displayed.
How would I modify the above command to take the full number after the '/'. Alternatively, if there is a nicer/better way to do this id be happy to hear it
Note: The number in bold has a range of 1-99
Using sed
$ sed -E 's#.*/([[:digit:]]+).*#\1#' input_file
15

notepad++ - search and replace for a word and remove line

hopefully I can make this understandable:
Just say I have this text in a file:
bash-4.2$ 336
1
bash-4.2$ 401
2
bash-4.2$ 403
3
bash-4.2$ 404
4
bash-4.2$ 735
5
bash-4.2$ 894
6
bash-4.2$ 909
7
I want to remove everything on the lines that start "bash", so I am looking for this output:
1
2
3
4
5
6
7
I have been using the regular expression search (with the help of https://regex101.com/r/kT0uE3/1) and if I use this search "bash.*" it removes the line but not the carriage return.
When I change this search to "bash.*\n" it does not find anything (despite regex101 saying it would work).
I think I am missing something obvious and simple but I cannot see the trees for the woods.
Any help is much appreciated.
Ctrl+H
Find what: ^bash-.+\R
Replace with: LEAVE EMPTY
CHECK Match case
CHECK Wrap around
CHECK Regular expression
UNCHECK . matches newline
Replace all
Explanation:
^ # beginning of line
bash- # literally
.+ # 1 or more any character but newline
\R #any kind of linebreak
Screenshot (before):
Screenshot (after):

Bash Script - String Split Paragraph Into Sentences

I'm trying to write a prepare-commit-msg git hook script to check the contents of the last 10 commit messages and check to see if the message that you are attempting to enter is unique and prevent the user from checking in (without the --no-verify overload) if it detects it. When I run this command line in Git I get the following output.
dacke#MachineName /c/Development/Project (tests)
$ git log --pretty=format:'%h|%an|%s' --max-count=10
2919dc2|Eric|Test Message
4ef580c|Eric|Test Message
1a0051b|Eric|Test Message
3e2df42|Eric|Test Commit
a08d4c1|Bob|DE6717 - What I did to fix this defect
aff8afc|Bob|DE6717 - Here is some more defect info
bbbfb67|Ralph|Merge branch 'clean_up' into develop
72d0968|Ralph|Forgot to remove deleted class from the project.
bfd1505|Ralph|Clean up.
d21c6dc|Bruce|Merge branch 'Icons' into develop
My prepare-commit-msg is written like so.
1 #!/bin/bash
2
3 printf "Prepare-Commit-Msg Hook Running...\n"
4
5 #$1 = "Commit Message File 'COMMIT_EDITMSG'"
6 #$2 = "message"
7 commitMessage=$(cat "$1")
8
9 # Prevent people putting in the same commit message multiple times by looking for an identical message in the last 10 commits
10 declare -a last10CommitMessages
11 rawMessages=$(git log --pretty=format:'%h|%an|%s«' --max-count=10)
12 printf "Raw Messages Length: %d\n" "${#rawMessages[#]}"
13 for line in ${rawMessages//«/ };
14 do
15 #printf "%s\n" $line
16 last10CommitMessages+=($line);
17 done
18 printf "Last 10 Commit Length: %d\n" "${#last10CommitMessages[#]}"
19
20 # Temp exit 1 to prevent commit during testing
21 exit 1
When I try to run the "commit" I get the following output.
Raw Messages Length: 1
Last 10 Commit Length: 63
If I uncomment line 15 I can see that for every space and line break I'm getting an item added to the array. On top of that the character that I actually wanted to split the lines on is added to the end which means that I would need yet another method to take this off the end.
I am new to bash scripting and I'm coming from a C# / Windows background so I still learning. Can someone please provide me a simple solution to the problem? More important to me than a quick answer is an answer that can explain HOW this actually works. I've found a lot of conflicting information that does not work for me on the web. I plan on writing a blog piece about this after I get it all figured out so it's important that I don't get any "It just works" as an answer. Thanks.
Simply change
rawMessages=$(git log --pretty=format:'%h|%an|%s«' --max-count=10)
to this
rawMessages=($(git log --pretty=format:'%h|%an|%s«' --max-count=10))
$( ) evaluates the command inside and saves it as one string, ignoring line breaks. When you wrap something with ( ), it evaluates the contents as an array.
EDIT:
If you do this you will see you have way more elements in the array than you wanted. This is because the array will split the string by new line character and white space. To ignore white space you can do as hlovdal suggested and do this..
OLD_IFS="$IFS"
IFS=$'\n'
rawMessages=($(git log --pretty=format:'%h|%an|%s«' --max-count=10))
IFS="$OLD_IFS"
The words are split due to the IFS variable (Internal Field Separator - an ancient unix relic...) which has default value "<space><tab><newline>". Change your loop to
oldIFS=$IFS
IFS=«
for line in ${rawMessages}
do
printf "%s\n" $line
last10CommitMessages+=($line);
done
IFS=$oldIFS

How to write a Linux script to run multiple files from a single executable?

I have an executable which works on a file & produces another file. I need to provide the first entry of the file as an argument of the executable. Suppose the executable name is "myexec" and I am trying to run a file "myfile.extension"
"myfile.extension" has a format like this:
7 4 9 1 4 11 9 2 33 4 7 1 22 4 55 ...
While running the executable, I have to type the following:
myexec 7 myfile.extension
and it produces a file named myfile.extension.7
My question is that how can I write a script that will do this for a bunch of files in a directory?
Here's a bash script that you can execute in the directory with the files. It assumes the first word in the file is the argument:
for f in *
do
i=$(awk 'NR==1{print $1;exit}' $f)
myexec $i myfile.extension
done
Edit: Using awk instead of cut | head. Mentioned by brianadams in the comments.

Extracting IP addresses from text file with batch

I have a text file with data like this:
Aug 21 [10.23.5.5] Teardown dynamic
Aug 18 [10.150.1.45] Aug 21 15:28:34 otoldc
Aug 24 [10.96.5.10] Aug 21 2012 18:58:26 HYD
Aug 24 [10.96.5.10] Aug 22 2012 18:58:26 HYD
Aug 21 [192.168.15.231] sendmail[18831]
I need to remove everything except IP addresses surrounded by "[" and "]". String length before "[" is fixed. String length after "]" varied.
I tried use one of existing solutions here but couldn't get success. Is it possible to do it using batch?
Thanks:-)
directly from command line: for /f "tokens=2 delims=[]" %F in (file.txt) do echo %F. Redirect as you wish.
Not as flexible as sed/awk & regexes, but it does not require external tools.
If you plan to put together something more complex though, I would really look to more powerful tools - apart from already mentioned awk or Perl natural choice on Win would be Powershell.
Install a version of sed if it's not already on your system.
$ sed -r -e 's/^[^[]*\[([^]\]*)].*/\1/' file.txt
10.23.5.5
10.150.1.45
10.96.5.10
10.96.5.10
192.168.15.231
This sed one-liner 'script' outputs each input line after removing everything from the lines except the contents inside the first set of [] square brackets on the line - it does not check those contents to make sure it matches an IP address.
You tagged this as batch, so I assume this is on Windows and not linux. All the same, I'd highly recommend you head over to Cygwin's website and download a copy. This will give you access to the cat and grep commands, which make this much simpler. Once you have Cygwin installed, you can run the following command to parse out the IP addresses from your log file.
cat your.log | grep -oE '([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}' > ips.txt
Cheers

Resources