I use below to replace text on line numbers 29 to 32:
sed -i '29,32 s/^ *#//' file
How can I further add line numbers i.e. line 35 to 38, line 43 & line 45 in above command?
With GNU sed. m is here a label.
sed -i '29,32bm;35,38bm;43bm;45bm;b;:m;s/^ *#//' file
From man sed:
b label: Branch to label; if label is omitted, branch to end of script.
: label: Label for b and t commands.
This might work for you (GNU sed):
cat <<\! | sed 's:$:s/^ *#//:' | sed -f - -i file
29,32
35,38
43,45
!
Create a here-document with the line ranges you desire and pass these to a sed script that creates another sed script which is run against the desired file.
The here-document could be replaced by a file:
sed 's:$:s/^ *#//:' lineRangeFile | sed -f - -i file
Related
file xz.txt
123
456
789
I want to merge
sed -i '1d' xz.txt
sed -i '1a abc' xz.txt
I tried
sed -i -e '1d' -e '1a abc' xz.txt
expect to get
456
abc
789
but I got
456
789
sed (GNU sed) 4.7
but it doesn't work, any help?
Sed goes line by line, first command 1d - deleted 1st line, 1st line is gone, there is no more 1st line, that is why second command 1a abc didn't work. Here is how it should be:
$ sed '1d; 2a abc' f
456
abc
789
What is going on is that the delete statement automatically ends the processing sequence:
[1addr]a\
text Write text to standard output as described previously (yes there is a new-line here)
[2addr]d: Delete the pattern space and start the next cycle
Source: Posix)
As the a command does not modify the pattern space but just writes to stdout, you can simply do
[POSIX]$ sed -e '1a\
abc' -e '1d'
[GNU]$ sed -e '1a abc' -e '1d'
However, the easiest is just to use the replace command c:
[POSIX]$ sed -e '1c\
abc'
[GNU]$ sed -e '1c abc`
Note: The reason the commands a and c write directly to the output and not to the pattern space is most likely that it would mess up the address ranging using line-numbers.
I want to print only line 49 and substitute ',' for tab (ideally with sed).
sed -n '49p' file.txt | sed 's/,/\t/g'
How do I do it in one command without piping?
sed -n '49p; s/,/\t/g' would not work, neither sed '49p; s/,/\t/g'.
Thank you!
49 is an address and p and s// are commands. You can prefix any command by an address. So, instead of using just p on line 49 use s/// first:
sed -n '49s/,/\t/gp' file
Note that in this case p is just a flag for s/// and not the actual p command. For the more general case of arbitrary commands, you can repeat the address for each command 49s/,/\t/g; 49p or group the command behind one address 49 { s/,/\t/g; p }.
As pointed out in the comments you can speed up the command by exiting sed after line 49, so that the rest of the file isn't processed anymore (similar to head -n 49 | sed):
sed -n '49 { s/,/\t/gp; q }' file
You could delete any line that is not line 49, which ignores the rest of the sed commands except on line 49:
sed '49!d;s/,/\t/g' file.txt
If you want to do it with awk, you can use
awk 'NR==49{gsub(/,/,"\t");print;exit}' file
The NR==49 will check if Line 49 is being processed, and if yes, gsub(/,/,"\t") will replace each comma with a tab char in the line, and print will show it and exit will stop awk from processing further lines.
This might work for you (GNU sed):
sed '49!d;y/,/\t/;q' file
If it is not line 49, delete it.
If it is line 49, translate commas to tabs and quit.
Due to the know prob of mocha-lcov-mocha breaking file paths, I need to fix the current output paths that looks like this:
SF:Vis/test-Guid.coffee
SF:Vis/Guid.coffee
SF:Vis/test-Vis-Edge.coffee
SF:Vis/Vis-Edge.coffee
into
SF:test/Vis/test-Guid.coffee
SF:src/Vis/Guid.coffee
SF:test/Vis/test-Vis-Edge.coffee
SF:src/Vis/Vis-Edge.coffee
I'm not very good with sed, but I got it to work using:
mocha -R mocha-lcov-reporter _coverage/test --recursive | sed 's,SF:,SF:src/,' | sed s',SF.*test.*,SF:test//&,' | sed s',/SF:,,' | sed s',test/src,test,' | ./node_modules/coveralls/bin/coveralls.js
which is basically doing 4 sed commands in sequence
sed 's,SF:,SF:src/,'
sed s',SF.*test.*,SF:test//&,'
sed s',/SF:,,'
sed s',test/src,test,'
my question is if there is a way to do with this one sed command, or use another osx/linux command line tool
Initially put "src/" after every ":" and then if "test" is found on the line replace "src" with "test":
$ sed 's,:,:src/,;/test/s,src,test,' file
SF:test/Vis/test-Guid.coffee
SF:src/Vis/Guid.coffee
SF:test/Vis/test-Vis-Edge.coffee
SF:src/Vis/Vis-Edge.coffee
You could put all the sed commands in a file, one line per command, and just use "sed -e script". But if you just want it on a single command-line, separate with semicolons. This works for me:
sed 's,SF:,SF:src/,;s,SF.*test.*,SF:test//&,;s,SF:,,;s,test/src/,test,'
sed command
sed '\#test#!{s#SF:Vis/#SF:src/Vis/#g};\#SF:Vis/test#{s#SF:Vis/test#SF:test/Vis/test#g};' my_file
Here is an awk version:
awk -F: '/SF/ {$0=$1FS (/test/?"test/":"src/")$2}1' file
SF:test/Vis/test-Guid.coffee
SF:src/Vis/Guid.coffee
SF:test/Vis/test-Vis-Edge.coffee
SF:src/Vis/Vis-Edge.coffee
How it works:
awk -F: ' # Set field separator to ":"
/SF/{ # Does line start with "SF"?
$0=$1FS (/test/?"test/":"src/")$2 # Recreat String by adding "test" if line contains "test", else "src"
}
1 # Print all lines
' file # read the file
I have 'file1' with (say) 100 lines. I want to use sed or awk to print lines 23, 71 and 84 (for example) to 'file2'. Those 3 line numbers are in a separate file, 'list', with each number on a separate line.
When I use either of these commands, only line 84 gets printed:
for i in $(cat list); do sed -n "${i}p" file1 > file2; done
for i in $(cat list); do awk 'NR==x {print}' x=$i file1 > file2; done
Can a for loop be used in this way to supply line addresses to sed or awk?
This might work for you (GNU sed):
sed 's/.*/&p/' list | sed -nf - file1 >file2
Use list to build a sed script.
You need to do > after the loop in order to capture everything. Since you are using it inside the loop, the file gets overwritten. Inside the loop you need to do >>.
Good practice is to or use > outside the loop so the file is not open for writing during every loop iteration.
However, you can do everything in awk without for loop.
awk 'NR==FNR{a[$1]++;next}FNR in a' list file1 > file2
You have to >>(append to the file) . But you are overwriting the file. That is why, You are always getting 84 line only in the file2.
Try use,
for i in $(cat list); do sed -n "${i}p" file1 >> file2; done
With sed:
sed -n $(sed -e 's/^/-e /' -e 's/$/p/' list) input
given the example input, the inner command create a string like this: `
-e 23p
-e 71p
-e 84p
so the outer sed then prints out given lines
You can avoid running sed/awk in a for/while loop altgether:
# store all lines numbers in a variable using pipe
lines=$(echo $(<list) | sed 's/ /|/g')
# print lines of specified line numbers and store output
awk -v lineS="^($lines)$" 'NR ~ lineS' file1 > out
I have a file called test.csv with the following content:
T1,T2,T3,T4
10,2,3,17
10,2,5,14
10,2,2,16
15,1,17,15
12,1,9,25
I want to replace all the values 17 on the fourth column by 25. So I tried the command:
cat test.csv | sed -r 's/(([1-9]+,){3})17/\125/g'
T1,T2,T3,T4
10,2,3,17
10,2,5,14
10,2,2,16
15,1,17,15
12,1,9,25
As you can see, only the last row was modified, but not the second.
However, if I do: cat test.csv | sed -r "s/([0-9]+,[0-9]+,[0-9]+,)17/\125/" I have the output I want. Why is that?
The reason your sed line didn't work is:
if you check your sed line carefully,
cat test.csv | sed -r 's/(([1-9]+,){3})17/\125/g' (your sed line)
you had [1-9] not [0-9], fix that and try again, it should work for you.
also the cat file is not required. you can do sed '...' file