sed - pass match to external command
if your sed is GNU sed. you can use 'e' to pass matched group to external command/tools within sed command.
an example might be helpful to make it clear:
say, you have a problem:
you have a string "120+20foobar"
now you want to get the calculation result of 120+20 part, and replace "oo" to "xx" in "foobar" part.
Note that this example is not for solving the problem above, just for
showing the sed 'e' usage
so you could make 120+20
in the first match group, and rest in 2nd group, then pass two groups to different command/tools and then get the result. like:
kent$ echo "100+20foobar"|sed -r 's#([0-9+]*)(.*)#echo \1 \|bc\;echo \2 \| sed "s/oo/xx/g"#ge'
120
fxxbar
in this way, you could nest many seds one in another one, till you get lost. :D
How do I push `sed` matches to the shell call in the replacement pattern?
So you are trying to call an external command from inside the replacement pattern of a sed substitution. I dont' think it can be done, the $... inside a pattern just allows you to use an already existent (constant) shell variable.
I'd go with Perl, see the /e option in the search-replace operator (s/.../.../e).
UPDATE: I was wrong, sed plays nicely with the shell, and it allows you do to that. But, then, the backlash in \1
should be escaped. Try instead:
sed "s/^URL=\(.*\)/TITLE=$(curl -s \\1 | head -n 1)/" file.txt
How to find/replace and increment a matched number with sed/awk?
I think finding file isn't the difficult part for you. I therefore just go to the point, to do the +1 calculation. If you have gnu sed, it could be done in this way:
sed -r 's/(.*)(\?cache_version=)([0-9]+)(.*)/echo "\1\2$((\3+1))\4"/ge' file
let's take an example:
kent$ cat test
ello
barbaz?cache_version=3fooooo
bye
kent$ sed -r 's/(.*)(\?cache_version=)([0-9]+)(.*)/echo "\1\2$((\3+1))\4"/ge' test
ello
barbaz?cache_version=4fooooo
bye
you could add -i option if you like.
edit
/e
allows you to pass matched part to external command, and do substitution with the execution result. Gnu sed only.
see this example: external command/tool echo
, bc
are used
kent$ echo "result:3*3"|sed -r 's/(result:)(.*)/echo \1$(echo "\2"\|bc)/ge'
gives output:
result:9
you could use other powerful external command, like cut, sed (again), awk...
Match a line and return a previous line before the match containing a pattern
This sed command should extract it:
sed -n '
/^Id: / { # If the line starts with "Id: "
s/// # Remove the "Id: "
h # Store what is left in the hold space
}
/^ email: '"$email"'/ { # If the line starts with " email: " plus the email
x # Swap pattern and hold space
p # Print pattern space
q # Stop processing
}
' infile
where $email
is the shell variable containing the escaped version of test_1@somedomain.com
:
raw='test_1@somedomain.com'
email=$(sed 's|[]/.*^$\[]|\\&|g' <<< "$raw")
This escapes the sed special characters .*/^$[]\
.
Or, more compact:
sed -n '/^Id: /{s///;h};/^ email: '"$email"'/{x;p;q}' infile
macOS sed requires an extra ;
before each closing }
.
And yes, it's probably easier with awk /p>
Sed replace with the output of a bash command using capture group as argument
You can use e
in GNU sed
to pass the substitution string to a shell for evaluation. This way, you can say:
printf "%s %s" "something" "\1"
Where \1
holds a captured group. All together:
$ sed -r 's#match_([0-9]*).*#printf "%s %s" "something" "\1"#e' <<< "match_555 hello"
something 555
This comes handy when you want to perform some shell action with a captured group, like in this case.
So, let's capture the first part of the line, then the part that needs to be encoded and finally the rest. Once this is done, let's print those pieces back with printf
triggering the usage of base64 -d
against the second slice:
$ sed -r '/^Base64/s#(.*;)([^\&]*)(&.*)# printf "%s%s%s" "\1" $(echo "\2" | base64 -d) "\3";#e' file
someline
someline
Base64Expression stringValue="foo"
someline
Base64Expression stringValue="bar"
Step by step:
sed -r '/^Base64/s#(.*;)([^\&]*)(&.*)# printf "%s%s%s" "\1" $(echo "\2" | base64 -d) "\3";#e' file
# ^^^^^^^ ^^^ ^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ ^
# | first part | the rest encode the 2nd captured group |
# | | |
# | important part execute the command
# |
# on lines starting with Base64, do...
The idea comes from this superb answer by anubhava on How to change date format in sed?.
Trying to change date string in a file to different format with sed
In your example, you use simple quote to protect the sed expression, that's why you CANNOT use other simple quote inside (there is no escape in this case).
If your sed is GNU sed. you can use 'e' to pass matched group to external command/tools within sed command as explained here.
But it means you call an external command for each match. So this solution can be slow if your text contains a lot of dates.
If you have only one date by line, I suggest the following script :
sed -r 's#([0-9]{1,2})-([0-9]{1,2})-([0-9]{4})#date -d"\1/\2/\3" +"%B %d, %Y"#e'
Multiple mathematical operations on a file containing numbers
For calculations, use awk
!
$ awk '{$(NF-1)=sprintf("%.0f", ($(NF-1) + $NF)/2 * 141); NF--}1' file
AJ29 IO_0_VRN_10 10945
AJ30 IO_L1P_T0_100M 12738
AJ31 IO_L1N_T0_100S 14367
AK29 IO_L2P_T0_101M 9376
AL29 IO_L2N_T0_101S 9016
This replaces the penultimate field with the result of (penultimate*last)/2 * 141)
. To make it round, we use %.0f
format as indicated in Awk printf number in width and round it up.
Also, it looks to me that you are piping way too many things: I counted one call to grep
and 13 (!) to sed
. You can probably use sed -e 'first block' -e 'second block' ...
instead.
Explanation
In awk
, NF
refers to the number of fields on the current line. Since $n
refers to the field number n
, with $(NF-1)
we refer to the penultimate field.
{...}1
do stuff and then print the resulting line.1
evaluates as True and anything True triggersawk
to perform its default action, which is to print the current line.$(NF-1) + $NF)/2 * 141
perform the calculation: `(penultimate + last) / 2 * 141{$(NF-1)=sprintf( ... )
assign the result of the previous calculation to the penultimate field. Usingsprintf
with%.0f
we make sure the rounding is performed, as described above.{...; NF--}
once the calculation is done, we have its result in the penultimate field. To remove the last column, we just say "hey, decrease the number of fields" so that the last one gets "removed".
Related Topics
How to Use Iptables in Linux to Forward Http and Https Traffic to a Transparent Proxy
Sort by Multiple Columns in Bash
Print Previous Line If Condition Is Met
Displaying Webcam Video with Qt
Grep Files Based on Time Stamp
Aws-Ec2, How to Set Multiple Public Sites with Just One Instance
Linux - Save Only Recent 10 Folders and Delete The Rest
Shared Library in Fortran, Minimal Example Does Not Work
How to Find The Processor Queue Length in Linux
How to Wake Select() on a Socket Close
Save in a Variable The Number of Seconds a Process Took to Run
Recursively Kill R Process with Children in Linux
Getting Memory Map of Every Device in Linux
Apache Webserver - How to Write to Dir/Files with Permissions Set at 755 Instead of 777
Linux Kernel: What Process Does Schedule() Run In