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.
Related
I want to get the first line of a file that is not commented out with an hash, then append a line of text just after that line just before that line.
I managed to get the number of the line:
sed -n '/^\s*#/!{=;q}' file // prints 2
and also to insert text (specifying the line manually):
sed '2 a extralinecontent' file
I can't get them working together as a one liner or in a batch.
I tried command substitution (with $(command) and also with backticks) but I get an error from bash:
sed '$(sed -n '/^\s*#/!{=;q}' file) a extralinecontent' file
-bash: !{=: event not found
and also tried many other combinations, but no luck.
I'm using gnu-sed (via brew) on macOS.
This might work for you (GNU sed):
sed -e '/^\s*#/b;a extra line content' -e ':a;n;ba' file
Bail out of any lines beginning with a comment at the beginning of the file, append an extra line following the first line that is not a comment and keep fetching/printing all the remaining lines of the file.
Here's a way to do it with GNU sed without reading the file twice
$ cat ip.txt
#comment
foo baz good
123 456 7889
$ sed -e '0,/^\s*[^#[:space:]]/ {// a XYZ' -e '}' ip.txt
#comment
foo baz good
XYZ
123 456 7889
GNU sed allows first address to be 0 if the other address is regex, that way this will work even if first line matches the condition
/^\s*[^#[:space:]]/ as sed doesn't support possessive quantifier, need to ensure that the first character being matched by the character class isn't either a # or a whitespace character
// is a handy shortcut to repeat the last regex
a XYZ your required line to be appended (note that your question mentiones insert, so if you want that, use i instead of a)
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
I have a file in which some lines start by a >
For these lines, and only these ones, I want to keep the first eleven characters.
How can I do that using sed ?
Or maybe something else is better ?
Thanks !
Muriel
Let's start with this test file:
$ cat file
line one with something or other
>1234567890abc
other line in file
To keep only the first 11 characters of lines starting with > while keeping all other lines:
$ sed -r '/^>/ s/(.{11}).*/\1/' file
line one with something or other
>1234567890
other line in file
To keep only the first eleven characters of lines starting with > and deleting all other lines:
$ sed -rn '/^>/ s/(.{11}).*/\1/p' file
>1234567890
The above was tested with GNU sed. For BSD sed, replace the -r option with -E.
Explanation:
/^>/ is a condition. It means that the command which follows only applies to lines that start with >
s/(.{11}).*/\1/ is a substitution command. It replaces the whole line with just the first eleven characters.
-r turns on extended regular expression format, eliminating the need for some escape characters.
-n turns off automatic printing. With -n in effect, lines are only printed if we explicitly ask them to be printed. In the second case above, that is done by adding a p after the substitute command.
Other forms:
$ sed -r 's/(>.{10}).*/\1/' file
line one with something or other
>1234567890
other line in file
And:
$ sed -rn 's/(>.{10}).*/\1/p' file
>1234567890
I'm using sed to filter a list of files. I have a sorted list of folders and I want to get all lines after a specific one. To do this task I'm using the solution described here which works pretty well with any input I tried but it doesn't work when the match is on the first line. In that case sed will remove all lines of the input
Here it's an example:
$ ls -1 /
bin
boot
...
sys
tmp
usr
var
vmlinuz
$ ls -1 / | sed '1,/tmp/d'
usr
var
vmlinuz
$ ls -1 / | sed '1,/^bin$/d'
# sed will delete all lines from the input stream
How should I change the command to consider also the limit case when first line is matched by regexp?
BTW sed '1,1d' correctly works and remove the first line only.
try this (GNU sed only):
sed '0,/^bin$/d'
..output is:
$sed '0,/^bin$/d' file
boot
...
sys
tmp
usr
var
vmlinuz
This sed command will print all lines after and including the matching line:
sed -n '/^WHATEVER$/,$p'
The -n switch makes sed print only when told (the p command).
If you don't want to include the matching line you can tell sed to delete from the start of the file to the matching line:
sed '1,/^WHATEVER$/d'
(We use the d command which deletes lines.)
you can also try with :
awk '/searchname/{p=1;next}{if(p){print}}'
EDIT(considering the comment from Joe)
awk '/searchname/{p++;if(p==1){next}}p' Your_File
I would insert a tag before a match and delete in scope /start/,/####tag####/.
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