vim: macro to insert line number with some maths - vim

I've got a directory with more than 100 000 small files.
I'd like to put them into separate folders.
find mydir/ -type f | sort > tt.txt
vim tt.txt
Now I'd like for each line, to insert a number with this formulae:
(line number) + 50000 + ((line number/1000)*1000)
So the original file is something like:
abainville_55130_55001.htm
abancourt_59268_59001.htm
abbenans_25340_25003.htm
abergement-de-cuisery_71290_71001.htm
And should output:
51001 - abainville_55130_55001.htm
51002 - abancourt_59268_59001.htm
51003 - abbenans_25340_25003.htm
51004 - abergement-de-cuisery_71290_71001.htm
and so on until the 1000th line where
line 998 => 51000 - bannes_53340_53019.htm
line 999 => 51000 - bannieres_81500_81022.htm
line 1000 => 52000 - bannoncourt_55300_55027.htm
line 1001 => 52000 - banos_40500_40024.htm
line 1002 => 52000 - bans_39380_39037.htm
and after that I'll apply a macro to transform it to:
mv bannes_53340_53019.htm 51998/bannes_53340_53019.htm
mv bannieres_81500_81022.htm 51999/bannieres_81500_81022.htm
mv bannoncourt_55300_55027.htm 52000/bannoncourt_55300_55027.htm
mv banos_40500_40024.htm 52001/banos_40500_40024.htm
mv bans_39380_39037.htm 52002/bans_39380_39037.htm
(the last part is easy and not the problem, the problem is about maths).
I know there's something like but I can't find the solution to apply my maths:
:s/^/\=(line('.')+51000)/

You don't have to do the job in two steps, you could generate those "mv..." command lines with vim in one short, if you want to stick to vim.
try this line:
%s#.*$#\="mv ".submatch(0)." ".(line(".")+50000+((line(".")/1000)*1000)) . "/" . submatch(0)#
will generate something like: (if the first line is on line number 1)
mv abainville_55130_55001.htm 50001/abainville_55130_55001.htm
mv abancourt_59268_59001.htm 50002/abancourt_59268_59001.htm
mv abbenans_25340_25003.htm 50003/abbenans_25340_25003.htm
mv abergement-de-cuisery_71290_71001.htm 50004/abergement-de-cuisery_71290_71001.htm

You were nearly there. You can use the following command:
:%s/^/\=line('.')+51000 . " - "/
where % applies it to the whole file and . does string concatenation to get your spaced hyphen.
Edit:
In order to use / as part of the expression, you can change the delimiter character (see :help E146). For example, the following generates 51000 for 1000 lines, then 52000 for the next 1000 lines, and so on:
:s!^!\=50000 + (line('.') / 1000) * 1000 . " - "!

Related

copy output in front of specific characters (:*:) from each line in a list using Notepad ++ or in linux

I have a list where I would like to copy every word in from of :* on each line to create a new list.
for example
current list -
- ftp1:*:1737:199:User &:/home/ftp1:/bin/clish
- juan:*:1738:199:User &:/home/juan:/bin/clish
- kevin:*:1739:199:User &:/home/kevin:/bin/clish
- mailer:*:1740:199:User &:/home/mailer:/bin/clish
new list or file -
- ftp1
- juan
- kevin
- mailer
Ctrl+H
Find what: ^([^:]+).*$
Replace with: $1
Replace all
Explanation:
^ : begining of line
([^:]+) : group 1, every thing that is not a colon
.+ : 0 or more any character
$ : end of line
Replacement:
$1 : group 1
Result for given example:
ftp1
juan
kevin
mailer
cat inputfile | sed 's/:.*//' > outputfile
I would just delete everything from the first colon onward. I recommend you look for sed examples. There are many.

How to round up real number in text files in folders in windows or ubuntu

I have folder A which contains many subfolders: X, Y, Z, ...
in each of this folder X, Y, Z, has many text files have the content format like this:
1
323 267.6 572 444.6
Now I need to round up all the number to it's nearest integer value.
I already tried:
xargs -a numbers.txt -n1 printf "%1.f"
but it only to print out to the screen.
Now I need to replace the float numbers in the files in the exact position (exact line and position), not to print to screen. How should I do that ?
As I am using a lot vim, you can try with ex command (vi)
files=`find -L A -type f` ; for f in $files ; do ex -c 'silent! %s:\d+.\d*:\=printf("%.0f",str2float(submatch(0))):g' -c 'wq!' $f;
done
First it lists all files inside directory A and then it will round the floating number of the form d. and d.d where d is any sequence of digits.
The sample input will be converted to:
1
323 268 572 445
This solution is not beautiful but it let the work to be done (You may see the terminal blinking caused by -file opening->editing->saving)

insert symbol between numbers

I have a file in Linux OS containing some random numbers:
1
22
333
4444
55555
666666
7777777
88888888
Now, I have two conditions:
1. Remove last 3 digit from every entry and put / in between rest.
2. For the numbers <=3, just add/replace with / symbol.
command I am trying which fulfilling only 1st requirement is:
sed -e 's|\(.\)|\1/|g;s|\(.*\)/\(.\/\)\{3\}|\1|g'
Desired out required:
/
/
/
4
5/5
6/6/6
7/7/7/7
8/8/8/8/8
Please help.
Something like this might work for you:
% sed 's/.\{1,3\}$//;s/./\/&/g;s/.//;s/^$/\//' file
/
/
/
4
5/5
6/6/6
7/7/7/7
8/8/8/8/8
No smart moves here:
s/.\{1,3\}$//; # Remove last 3 character
s/./\/&/g; # Insert / before each character
s/.//; # Remove first character (it's now a /)
s/^$/\// # Insert slash on all empty lines
Alternative solution with gawk:
awk -v FS='' -v OFS='/' '{if (NF > 3) NF=(NF-3); else $0 = OFS}1' file
This might work for you (GNU sed):
sed -r 's/.{1,3}$//;s#\B#/#g' file
Remove the last three (or less) characters from the end of the line. Replace the void between characters with /'s.

Linux: How to insert a line at a specific line number in a file?

I'd like to add a specific line to a file in a specific line number (second) without over-writing the data which is already there.
I've tried this:
sed -i '2i - jstat' FILE
But this just over-writes the second line with "- jstat".
Instead, I want to add a new second line and push the next line to be number 3.
Let's say the file looks like that:
[root#puppet roles]# head -5 !$
head -5 buncher.yaml
classes:
- workspace
- fstab
- role_specific
I'd like to add a new module on the second line and I want the "workspace" module to become the third line.
More than that, I'd like the new line to start with a tab size of 2 chars and then "- jstat" as in: "TabTab - jstat", how can it be done?
Well to insert a line after before line number x, you can use the below sed command:
sed 'x i\LINE_TO_ADD' filename > temp_file
mv temp_file filename
Here is the example for adding <TAB><TAB>Hello How are you! to the tempfile whose content are:
123
234
345
To add before line number 2 I wrote the following sed command:
sed '2 i\\t\tHello How are you!' tempfile > temp_file
mv temp_file tempfile
Final content of tempfile are:
123
<TAB><TAB>Hello How are you!
234
345
For more detail, try referring this Sed tutorial

How can I swap two lines using sed?

Does anyone know how to replace line a with line b and line b with line a in a text file using the sed editor?
I can see how to replace a line in the pattern space with a line that is in the hold space (i.e., /^Paco/x or /^Paco/g), but what if I want to take the line starting with Paco and replace it with the line starting with Vinh, and also take the line starting with Vinh and replace it with the line starting with Paco?
Let's assume for starters that there is one line with Paco and one line with Vinh, and that the line Paco occurs before the line Vinh. Then we can move to the general case.
#!/bin/sed -f
/^Paco/ {
:notdone
N
s/^\(Paco[^\n]*\)\(\n\([^\n]*\n\)*\)\(Vinh[^\n]*\)$/\4\2\1/
t
bnotdone
}
After matching /^Paco/ we read into the pattern buffer until s// succeeds (or EOF: the pattern buffer will be printed unchanged). Then we start over searching for /^Paco/.
cat input | tr '\n' 'ç' | sed 's/\(ç__firstline__\)\(ç__secondline__\)/\2\1/g' | tr 'ç' '\n' > output
Replace __firstline__ and __secondline__ with your desired regexps. Be sure to substitute any instances of . in your regexp with [^ç]. If your text actually has ç in it, substitute with something else that your text doesn't have.
try this awk script.
s1="$1"
s2="$2"
awk -vs1="$s1" -vs2="$s2" '
{ a[++d]=$0 }
$0~s1{ h=$0;ind=d}
$0~s2{
a[ind]=$0
for(i=1;i<d;i++ ){ print a[i]}
print h
delete a;d=0;
}
END{ for(i=1;i<=d;i++ ){ print a[i] } }' file
output
$ cat file
1
2
3
4
5
$ bash test.sh 2 3
1
3
2
4
5
$ bash test.sh 1 4
4
2
3
1
5
Use sed (or not at all) for only simple substitution. Anything more complicated, use a programming language
A simple example from the GNU sed texinfo doc:
Note that on implementations other than GNU `sed' this script might
easily overflow internal buffers.
#!/usr/bin/sed -nf
# reverse all lines of input, i.e. first line became last, ...
# from the second line, the buffer (which contains all previous lines)
# is *appended* to current line, so, the order will be reversed
1! G
# on the last line we're done -- print everything
$ p
# store everything on the buffer again
h

Resources