Find and _modify_ text using regular expressions - sed

I have a lot of files like "some_text some_number.jpg", for example:
blabla 1.ext
blabla 22.ext
blabla 323.ext
And I need to rename thies to "some_text some_number-some_number+1.jpg":
blabla 1-2.ext
blabla 22-23.ext
blabla 323-324.ext
How can I use \1 like integer variable?
Of couse this code is wrong:
for fn in *; do new_fn=$(echo $fn|sed 's/ \([0-9]*\)/ \1-\1\++/'); mv $fn $new_fn; done
blabla 1-1++.ext
blabla 22-22++.ext
blabla 323-323++.ext

How can I use \1 like integer variable?
It is impossible to use anything as integer in sed. It is impossible to do arithmetic operations in sed. Use something else. Bash, Python, Perl, etc.
Try, untested, however should give you a hint what algorithm you might want to implement:
for fn in *; do
# split on space and dot!
IFS=' .' read -r pre num post <<<"$fn"
newnum=$((num + 1))
echo mv "$fn" "$pre $newnum.$post"
done

This might work for you (GNU sed & bash):
sed -E 's/(.* )([0-9]+)(\.ext)/echo "\1\2-$((\2+1))\3"/e' file

Related

Matching line subfield deliminated with square brackets

I have a file that contains lines that contains fields delimited with square brackets, for example :
[tag "x"][severity "y"][id "z"][client 1]
I need to extract the data from the client field. But I am struggling with the best way to do this. Obviously its too advanced for the likes of cut.
I have been struggling to use sed (and I'm not even sure sed is the "best" or "most appropriate" tool), but sed regex like this doesn't seem to work :
sed 's/^.*\[client\(.*\)/\1/g'
I'm guessing the "most appropriate" tool is probably Perl with some sort of Perl module ?
In Perl, you can capture each bracket contents like so:
$ perl -lne 'print $1 while /(?<=\[)([^\]]+)(?=\])/g' file
tag "x"
severity "y"
id "z"
client 1
So then if you only want the client match you can do:
$ perl -lne 'for (/(?<=\[)([^\]]+)(?=\])/g) { print if /^client\b/ }' file
client 1
As pointed out in comments, /\[([^\]]+)\]/g is maybe a little more efficient.
$ perl -lne 'for (/\[([^\]]+)\]/g) { print if /^client\b/}' file
client 1
You don't show your expected output so it's a guess but based on what it looks like the script you posted is attempting to do - is this what you want?
$ sed 's/.*\[client *\([^]]*\).*/\1/g' file
1
I would use tr -d.
echo '[tag "x"][severity "y"][id "z"][client 1]' | tr -d '[]'
tag "x"severity "y"id "z"client 1
echo '[tag "x"][severity "y"][id "z"][client 1]' | awk -F'[][]+' '{print $5}'
client 1

Substitute all occurrences of n spaces with a single character

I would like to use sed (is this the best tool?) to go from this:
foo bar buzz fuzz
to this:
foo|bar|buzz|fuzz
How can this be done ?
Many thanks :).
$ sed 's/\s\s*/|/g' < input
Assuming you have 5 spaces between your items and they are in a file called test.txt:
sed -i "s/ /|/g" test
Use the [:SPACE:] POSIX Class
If the number of spaces could change, or might be a mix of spaces and tabs, then you want to use a POSIX class to replace a series of whitespace characters with a single pipe symbol globally within the current pattern space. For example:
$ echo 'foo bar buzz fuzz' | sed 's/[[:space:]]\+/|/g'
foo|bar|buzz|fuzz
If you have GNU sed:
sed -r 's/ +/|/g'

Sed - Capitalize First character of a string ended in a dot

I need to capitalize (no matter what size of the string (4, 3, 2 or 1)) strings ended in a dot. But, the strings that do not end in a dot bust be kept in lowercase.
These 3 commands were capable of doing what i needed, but in 1-char strings ended in dot, and 2-char strings ended in dot.
sed -i -e "/<b>/ {s/\.\([^ ]\)/. \1/g}" file
sed -i -e "/<b>/ {s/\( [a-z]\.\)/\U\1/g}" file
sed -i -e "/<b>/ {s/\([a-z][^ ]\.\)/\u&/g}" file
following my stream, i tought that doing this (below), would make pretty much sense, but it did \not\ worked, and made the 3-char strings look like this: YEs. and the 4-char strings like HAHa.
sed -i -e "/<b>/ {s/\([a-z][^ ][^ ]\.\)/\u&/g}" file
Can someone help? :p (if possible, point me what have i done wrong)
This seems to do what you want:
sed '/<b>/{s/[a-z]*\./\u&/}' input
In your case, [a-z][^ ][^ ]\. only matches 3 letters or more. Instead of forcing the existence of [^ ]'s you can use * to make them optional: [a-z][^ ]*

Looking for a Perl or sed one-liner to replace a string with contents from another file

In an HTML file, let’s call it index.html, I want to replace a comment string, say //gac goes here, with the contents (multi-line) from a separate file which is called: gac.js. Is there a nice one-liner for that?
I found something as: sed -e "/$str/r FileB" -e "/$str/d" FileA, but it is not working as promised.
I do like it as short as possible, as it will be called after an SVN revert (I don't want any of that google.script polluting my development environment).
This should work, even though it is nasty:
perl -pe 'BEGIN{open F,"gac.js";#f=<F>}s#//gac goes here##f#' index.html
In the case that gac.js is supposed to be dynamic:
perl -pe 's#//(\S+) goes here#open+F,"$1.js";join"",<F>#e' index.html
perl -mFile::Slurp -pe 's/\/\/(\w+) goes here/#{[File::Slurp::read_file("$1.js")]}/;'
Obviously requires File::Slurp
Not very nice, but seems to work:
cat index.html | perl -pe 'open(GAC, "gac.js");#gac=<GAC>;$data=join("", #gac); s/gac goes here/$data/g'
After going through man sed, this tutorial and some experimenting I came up with:
sed -i '\_//gac goes here_ {
r gac.js
d
}' index.html
Which does exactly what I want. It's not exactly a oneliner (if i make it one line i get: sed: -e expression #1, char 0: unmatched '{') which I don't understand. However expression above fits nicely in my update script.
Lessons learned: sed is very powerfull, -i behaves different on mac os x / linux, /string/ can easily be replaced with \[other delimiter]string[other delimiter].

How to globally replace strings in lines NOT starting with a certain pattern

I want to globally replace the string foo with the string bar, using sed. This should only be done for lines which do NOT start with the string ##Input.
I can't get it to work. I tried things like this but reached a point where I'm not sure if I know what I'm doing:
sed -i '/^##Input/ s/foo/bar/g' myfile
Please help!
You just need to negate the match using !:
sed -i '/^##Input/! s/foo/bar/g' myfile
You got to escape # as in \#.
An ugly answer for an ugly request (i.e. they get what they asked for):
echo \{
for file in *.json; do
sed -n '/^[\{\}]/! s/\([^\,]\)$/\1,/; /^[\{\}]/!p' $file
done
echo \{