Command substitution within sed expression
You can create a sed script from the error message catalog, then apply that sed script to the log file.
Basically, something along these lines:
sed 's/\(.*\), 0x\([0-9A-F]*\)$/s%ERRORID:0x\2%ERROR:\1%g/' errors.txt |
sed -f - logfile.txt
The output from the first sed script should be something like this:
s%ERRORID:0x00000001%ERROR:Out of memory%
s%ERRORID:0x00000002%ERROR:Stack overflow%
s%ERRORID:0x00000031%ERROR:values of beta may cause dom%
That is, a new sed script which specifies a substitution for each error code in the catalog.
There are different dialects of sed so this may require minor tweaking. The sed on Linux I believe should use backslash before grouping parentheses in regular expressions, and gladly tolerate standard input as the argument to the -f
option. This is not portable to other Unices, though (but you could substitute Perl for sed if you need portability).
*Edit: If the error messages are fairly static, and/or you want to read the log from standard input, save the generated script in a file;
# Do this once
sed 's/\(.*\), 0x\([0-9A-F]*\)$/s%ERRORID:0x\2%ERROR:\1%g/' errors.txt >errors.sed
# Use it many times
sed -f errors.sed logfile.txt
You could also add #!/usr/bin/sed -f
at the top of errors.sed
and chmod +x
it to make it into a self-contained command script.
Command substitution in sed
You should be able to do this with one sed
command:
read -rn 6 date < "$1"
sed -E 's#^([a-zA-Z]+)#'"$date"' \1#g' "$1" > newfile
The capture group ensures there's at least one character on the line before inserting the date.
EDIT: Based on the revision to your question:
newfile="output.txt"
lineone=$(head -1 "$1");
read -rn 6 date <<< "$lineone"
sed -E 's#^([a-zA-Z]+)#'"$date"' \1#g; 1s#^.*$#'"$lineone"'#' "$1" > "$newfile"
Since you aren't doing an in-place edit, you can do the $date insertions, and then go back and swap out the first line since it would end up with two dates. There might be "better" ways to do this such as using Perl
, or losing the second sed
command, although this should at least give you a basic idea though on how it works...
Result (newfile):
04/17 Walmart .toys $ 70 .cash $ -70
04/17 Caltex .gas 20 $ .cheque $ -20
04/17 McDonalds .burger 1 $ .cash $ -1
NOTE: In some versions of
sed
the option for extended regex can
either be-r
or-E
.
How to store sed arguments in variable for parameter substitution in BASH
Don't use a string, use an array:
myArgs=("-e" "s/foo/bar/" "-e" "s/foo2/bar2/")
sed "${myArgs[@]}" <<< "foo"
Use a variable as replacement in bash sed command
TL;DR:
Try:
sed -i '$ s@$@ '"$1"'@' "$DIR./result/doc.md"
Long version:
Let's start with your original code:
sed -i '$ s/$/ /replacement/' "$DIR./result/doc.md"
And let's compare it to the code you referenced:
sed -i '$ s/$/abc/' file.txt
We can see that they don't exactly match up. I see that you've correctly made this substitution:
file.txt --> "$DIR./result/doc.md"
That looks fine (although I do have my doubts about the . after $DIR ). However, the other substitution doesn't look great:
abc --> /replacement
You actually introduced another delimeter /. However, if we replace the delimiters with '@' we get this:
sed -i '$ s@$@ /replacement@' "$DIR./result/doc.md"
I think that the above is perfectly valid in sed/bash. The $@
will not be replaced by the shell because it is single quoted. The $DIR
variable will be interpolated by the shell because it is double quoted.
Looking at one of your attempts:
sed -i "$ s@$@ $1@" "$DIR./result/doc.md"
You will have problems due to the shell interpolation of $@ in the double quotes. Let's correct that by replacing with single quotes (but leaving $1 unquoted):
sed -i '$ s@$@ '"$1"'@' "$DIR./result/doc.md"
Notice the '"$1"'. I had to surround $1 with '' to basically unescape the surrounding single quotes. But then I surrounded the $1 with double quotes so we could protect the string from white spaces.
sed find and replace from line number
Using sed
$ sed "3c $(sed -n '3p' a.py)" b.py
import b
print('file a')
Use command substitution to allow another sed
command to be run as an arguments and c
to replace the contents of line 3.
Is it possible to pass a backreference to a function from inside sed?
How to properly escape a backreference in sed to pass it to a function?
The presented code properly handles the backreference. The backreference inside command substitution is not and will not be parsed by sed
, but by shell, before running sed
. The arguments to a program have to be expanded before running the program.
You may potentially use a GNU extension to sed
- the e
flag to s
command that executes the replacement pattern via /bin/sh
interpret. Using this flag is highly discouraged and is very hard to use, as figuring the correct quoting and escaping is very hard - it "works" in very simple cases. Because the input string has ;
<
>
and also "
special shell characters I doubt it's possible.
I suggest to pick a full fledged programming language, like python, perl or others, to solve your task. sed
is not an utility for dynamically executing actions depending on contents of the file, it's a simple stream replacement utility.
In sed
, it is possible to build a static list of strings to replace, like so:
sed -r '
s/(<CHARSET c="T">)02C8/\1'"$(echo -e "\u02C8")"/
s/(<CHARSET c="T">)0252/\1'"$(echo -e "\u0252")"/
.... one s/// command for each character to replace ...
'
Sed substitution on capture group
As mentioned in the comments, sed probably isn't needed.
Here's a pure bash version:
my_func(){
local cmd arg1 rest flags
if [[ $2 =~ [^a-zA-Z0-9] ]]; then
echo 1>&2 "bad character in arg2"
exit 1
fi
read -r cmd arg1 rest <<< $1
if [[ $arg1 =~ ^[^-] ]]; then
# no flags
echo "$cmd -$2 $arg1${rest:+ $rest}"
else
# have flags
# strip unwanted/duplicates and append new
eval 'flags=${arg1//[cd'$2']/}$2'
# append new flags and return
echo "$cmd $flags $rest"
fi
}
eval
is dangerous if passed untrusted data (as is your sed
using $2
unchecked) - always do a sanity check - I've assumed here that flags must be alphanumerics.
If you want to use sed, this should work (same caveat about sanity-checking $2
:
my_func(){
sed <<< $1 '
/^\([^ ][^ ]*\) \([^-]\)/ { # no flags
s//\1 -'$2' \2/;
q;
}
/^[^ ][^ ]* -\([^ ]*\) .*/ { # has flags
h;
s//\1/;
s/[cd'$2']//g;
G;
s/^\([^\n]*\)\n\([^ ][^ ]* -\)[^ ]*\( .*\)/\2\1'$2'\3/;
q;
}
{
s/.*/#ERROR: malformed input/;
q;
}
'
}
Related Topics
How to Set Umask Default for an User
Iptables Remove Specific Rules by Comment
How to Include Debug Information with Nasm
Extract Unique Block of Lines from a File Using Shell Script
Linux: Changing File Ownership Without a Copy
Sigbus While Doing Memcpy from Mmap Ed Buffer Which Is in Ram as Identified by Mincore
Some Flags About Workqueue in Kernel
Does a Fully Qualified Domain Name Need a Period
Slurm: After Allocating All Gpus No More CPU Job Can Be Submitted
How to Dynamic Load The Library with Same Name But in Different Directory in Linux
Register Hotkey with Only Modifiers in Linux
How Does Ltrace() Display Rand()
How to Ensure That a Process Runs in a Specific Physical CPU Core and Thread
How to Generate Files in a Docker Container for Having The Same Owner as The Host's User
Linux User Space Threads, Kernel Threads, Lightweight Processes