How to replace matching string by its content in parentheses in shell - shell

I'm trying to produce a shell script which is formatting commits in Shell.
After making a git log, I use grep to delete useless lines and now I want to change this :
feat(my-feat): my commit
to this:
my-feat: my commit
I want to write directly in a file: git log ... | grep -v ... >> CHANGELOG.md
Do you please have an idea how to achieve this ?
Thank you.

Using sed
$ sed 's/[^(]*(\([^)]*\))/\1/' input_file > new_file
$ cat new_file
my-feat: my commit

Related

To split the output(s) of a script into two fields and insert that output from a specific row in a csv file

I am trying to split the output of the following code into two fields and insert it from the 3rd row of a csv file
#!/bin/bash
cid=`git log -n 1 --pretty=format:"%H"`
git diff-tree --no-commit-id --name-only -r $cid | xargs -I {} echo '\'{} | xargs -I {} md5sum > final.csv
Current Output comes as a single line ( need to be separated into fields)
title,Path
l34sdg232f00b434532196298ecf8427e /path/to/file
sg35s3456f00b204e98324998ecsdf3af /path/to/file
Expected Output
final.csv
title,Path
l34sdg232f00b434532196298ecf8427e,/path/to/file
sg35s3456f00b204e98324998ecsdf3af,/path/to/file
I am thinking of placing the output of the script in a third file and then reading that file line by line using awk. Not sure if that's the correct way to proceed.
Thanks in advance.
You seem to be overcomplicating things.
#!/bin/sh
cid=$(git log -n 1 --pretty=format:"%H")
git diff-tree --no-commit-id --name-only -r "$cid" |
xargs md5sum |
sed 's/ /,/' > final.csv
This simply replaces the two spaces in the md5sum output with a comma.
Because nothing here is Bash-specific, I changed the shebang to #!/bin/sh; obviously, still feel free to use Bash if you prefer.
I also switched from the obsolescent `backtick` syntax to modern $(command substitution) syntax.
If you absolutely require the CSV header on top, adding that in the sed script should be trivial. Generally, header lines are more of a nuisance than actually useful, so maybe don't.
This kind of does what you're asking:
#!/bin/bash
cid=$(git log -n 1 --pretty=format:"%H")
git diff-tree --no-commit-id --name-only -r "$cid" | while read -r path
do
md5sum "${path}"
done | awk 'BEGIN{printf "%s,%s\n", "title", "path";printf "\n"}{printf "%s,%s\n",$1,$2}' > final.csv

What happens if error while doing "sed -i --" this is in place change of a file

I am trying to use sed -i -- for find and replace few strings in my file. What it there is error while doing the sed command, do the original file get corrupted ? or does it roll back to original file? . I know if i give sed -i"SUFFIX" --
it will create a backup file before changes but does it delete the backup file on successful execution of it ? or do we need to do that manually?.
I am looking for something in sed to make changes in place but on error or issue it needs to roll back all the changes until happened until then and give me back the original file as-is.
I can do it like below but looking for any optimized solution:
sed 's/abc/def/g' file1 > tmp_file
cp tmp_file file1
You've got a mis-understanding of how -i with the extension works in sed. Its sole purpose is to create a backup of the file as-is in-case when needed to revert back. Your requirement calls for this perfectly!
The backup file is never generated in-case your original command fails out of syntax errors when called. See the following
$ echo 'foo' > file
$ ls
file
$ cat file
foo
$ sed -i.bak 's/foo/bar/s' file
sed: -e expression #1, char 11: unknown option to `s'
$ cat file
foo
$ ls
file
As you can see, even in the forced command failure case, the backup file is not created.
$ sed -i.bak 's/foo/bar/g' file
$ cat file
bar
$ ls
file file.bak
$ cat file.bak
foo
But wait a moment, you've replaced incorrectly with bar, but you wanted to replace with foobar, now revert the file back
$ mv file.bak file
$ ls
file
$ cat file
foo

Adding a tab character before external script output

So, i've got a shell script to automate some SVN commands. I output to both a logfile and stdout during the script, and direct the SVN output to /dev/null. Now i'd like to include the SVN output in my logging, but to seperate it from my own output i'd like to prepend a \t to each line of the SVN output. Can this be done with shell scripting?
Edit
Is this something i could use AWK for? I'll investigate!
Edit
So, using AWK seems to do the trick. Sadly i can't get it to work with the svn commands though.
svn add * | awk '{ print "\t"$0 }'
Outputs without the prepended tab character. But if i run for example ls
ls -l | awk '{ print "\t"$0 }'
The directory is listed with a tab character in front of each line.
Edit
Thanks #daniel! I ended up with this
svn add * 2>&1 | sed 's/^/\t/'
Might aswell note that awk works well for this, when used correctly
svn add * 2>&1 | awk '{print "\t"$0 }'
You can use Sed. Instead of redirecting the output of your SVN command to /dev/null, you can pipe it to Sed.
svn ls https://svn.example.com 2>&1 | sed 's/^/ /'

sed command creates randomly named files

I recently wrote a script that does a sed command, to replace all the occurrences of "string1" with "string2" in a file named "test.txt".
It looks like this:
sed -i 's/string1/string2/g' test.txt
The catch is, "string1" does not necessarily exist in test.txt.
I notice after executing a bunch of these sed commands, I get a number of empty files, left behind in the directory, with names that look like this:
"sed4l4DpD"
Does anyone know why this might be, and how I can correct it?
-i is the suffix given to the new/output file. Also, you need -e for the command.
Here's how you use it:
sed -i '2' -e 's/string1/string2/g' test.txt
This will create a file called test.txt2 that is the backup of test.txt
To replace the file (instead of creating a new copy - called an "in-place" substitution), change the -i value to '' (ie blank):
sed -i '' -e 's/string1/string2/g' test.txt
EDIT II
Here's actual command line output from a Mac (Snow Leopard) that show that my modified answer (removed space from between the -i and the suffix) is correct.
NOTE: On a linux server, there must be no space between it -i and the suffix.
> echo "this is a test" > test.txt
> cat test.txt
this is a test
> sed -i '2' -e 's/a/a good/' test.txt
> ls test*
test.txt test.txt2
> cat test.txt
this is a good test
> cat test.txt2
this is a test
> sed -i '' -e 's/a/a really/' test.txt
> ls test*
test.txt test.txt2
> cat test.txt
this is a really good test
I wasn't able to reproduce this with a quick test (using GNU sed 4.2.1) -- but strace did show sed creating a file called sedJd9Cuy and then renaming it to tmp (the file named on the command line).
It looks like something is going wrong after sed creates the temporary file and before it's able to rename it.
My best guess is that you've run out of room in the filesystem; you're able to create a new empty file, but unable to write to it.
What does df . say?
EDIT:
I still don't know what's causing the problem, but it shouldn't be too difficult to work around it.
Rather than
sed -i 's/string1/string2/g' test.txt
try something like this:
sed 's/string1/string2/g' test.txt > test.txt.$$ && mv -f test.txt.$$ test.txt
Something is going wrong with the way sed creates and then renames a text file to replace your original file. The above command uses sed as a simple input-output filter and creates and renames the temporary file separately.
So after much testing last night, it turns out that sed was creating these files when trying to operate on an empty string. The way i was getting the array of "$string1" arguments was through a grep command, which seems to be malformed. What I wanted from the grep was all lines containing something of the type "Text here '.'".
For example the string, "Text here 'ABC.DEF'" in a file, should have been caught by grep, then the ABC.DEF portion of the string, would be substituted by ABC_DEF. Unfortunately the grep I was using would catch lines of the type "Text here ''" (that is, nothing between the ''). When later on, the script attempted to perform a sed replacement using this empty string, the random file was created (probably because sed died).
Thanks for all your help in understanding how sed works.
Its better if you do it in this way:
cat large_file | sed 's/string1/string2/g' > file_filtred

Extracting all lines from a file that are not commented out in a shell script

I'm trying to extract lines from certain files that do not begin with # (commented out). How would I run through a file, ignore everything with a # in front of it, but copy each line that does not start with a # into a different file.
Thanks
Simpler: grep -v '^[[:space:]]*#' input.txt > output.txt
This assumes that you're using Unix/Linux shell and the available Unix toolkit of commands AND that you want to keep a copy of the original file.
cp file file.orig
mv file file.fix
sed '/^[ ]*#/d' file.fix > file
rm file.fix
Or if you've got a nice shiny new GNU sed that all be summarized as
cp file file.orig
sed -i '/^[ ]*#/d' file
In both cases, the regexp in the sed command is meant to be [spaceCharTabChar]
So you saying, delete any line that begins with an (optional space or tab chars) #, but print everything else.
I hope this helps.
grep -v ^\# file > newfile
grep -v ^\# file | grep -v ^$ > newfile
Not fancy regex, but I provide this method to Jr. Admins as it helps with understanding of pipes and redirection.

Resources