I'm using Cmder on Windows and trying to execute the following statement:
echo "c:\Sources\" + (echo "Modules/ASR/branches/1.9" | sed -e "s|Modules/||")
Whenever I issue that command I get the annoying error
sed: -e expression #1, char 13: unknown option to `s'
But when I run the sed command on its own:
(echo "Modules/ASR/branches/1.9" | sed -e "s|Modules/||")
It magically works. Could anyone explain what I'm doing wrong?
Editor's note: This question was originally mis-tagged bash, whereas the symptom described implies cmd.
The error message in the question is due to windows cmd which splits the command with the | and adds closing parenthese ) to sed command.
cmd equivalent for "command substitution" is for /f followed by command between single quotes, pipe must be escaped with ^
for /f %x in ('echo "Modules/ASR/branches/1.9" ^| sed -e "s|Modules/||" ') do #echo "c:\Sources\"%~x
Or when used in script the percent must be doubled
for /f %%x in ('echo "Modules/ASR/branches/1.9" ^| sed -e "s|Modules/||" ') do #echo "c:\Sources\"%%~x
Otherwise expansion allows to replace pattern %var:pat=repl%
set mypath=Modules/ASR/branches/1.9
echo "c:\Sources\"%mypath:Modules/=%
in bash equivalent
echo 'c:\Sources\'"$(echo "Modules/ASR/branches/1.9" | sed -e "s|Modules/||")"
also to avoid to launch a new process this can be done with variable expansion # to remove shortest prefix.
mypath="Modules/ASR/branches/1.9"
echo 'c:\Sources\'"${mypath//Modules\/}"
Related
I have a sample.txt file with contents as:
test sometest
test2 againsometext
My shell script uses sed to find the line which has "test" and replaces the whole line with "test google.com::100-ws sample.com::SAMPLE". sed fails with "unterminated `s' command".
#!/bin/sh
TEST1=test
TEST2=google.com::100-ws sample.com::GOLD-WS
echo $TEST1
echo $TEST2
if [[ ! -e sample.txt ]]; then
touch sample.txt
echo $TEST1 $TEST2 >> sample.txt
else
grep -q $TEST1 sample.txt
if [ $? -eq 0 ];then
sed -i 's/^$TEST1 .*$/$TEST1 '$TEST2'/' sample.txt
else
echo $TEST1 $TEST2 >> sample.txt
fi
fi
I have this same script in other places where the replacement text does not have any spaces and it works fine.
Can someone suggest some ideas to try?
TIA
Assuming bash is available in your environment, it will be just
enough to say:
#!/bin/bash
test1="test"
test2="google.com::100-ws sample.com::GOLD-W"
sed -i "s/^$test1.*/$test1 $test2/" sample.txt
You need to quote strings which contain blank character(s) to prevent word-splitting.
It is not a good practice to use uppercase alphabets for normal variable names.
You need to use not single quotes but double quotes to enable variable expansion as
a command to sed.
That space between test and msg is important. Otherwise you'll obliterate every line that begins with test. Also you can backrefence \1 your captured group \(test \) https://regular-expressions.mobi/refcapture.html
#! /bin/bash
replace="google.com::100-ws sample.com::GOLD-W"
sed -i "s/^\(test \).*/\1$replace/" sample.txt
How do you escape line beginning and line end in bracket expressions in sed?
For example, let's say I want to replace both comma, line beginning, and line end in each line with pipe:
echo "a,b,c" | sed 's/,/|/g'
# a|b|c
echo "a,b,c" | sed 's/^/|/g'
# |a,b,c
echo "a,b,c" | sed 's/$/|/g'
# a,b,c|
echo "a,b,c" | sed 's/[,^$]/|/g'
# a|b|c
I would expect the last command to produce |a|b|c|. I also tried escaping the line beginning and line end via backslash, with no change.
With GNU sed with extended regular expressions, you can do:
$ echo "a,b,c" | /opt/gnu/bin/sed -E 's/^|,|$/|/g'
|a|b|c|
$
The -E option enables the extended regular expressions, as does -r, but -E is also used by other sed variants for the same purpose, unlike -r.
However, for reasons which elude me, the BSD (macOS) variant of sed produces:
$ echo "a,b,c" | sed -E 's/^|,|$/|/g'
|a|b|c
$
I can't think why.
If this variability is unacceptable, go with the three-substitution solution:
$ echo "a,b,c" | sed -e "s/^/|/" -e "s/$/|/" -e "s/,/|/g"
|a|b|c|
$
which should work with any variant of sed. However, note that echo "" | sed …3 subs… produces || whereas the -E variant produces |. I'm not sure if there's an easy fix for that.
You tried this, but it didn't do what you wanted:
$ echo "a,b,c" | sed 's/[,^$]/|/g'
a|b|c
$
This is what should be expected. Inside character classes, most special characters lose their special-ness. There is nothing special about $ (or , but it isn't a metacharacter anyway) in a character class; ^ is only special at the start of the class and it negates the character class. That means that what follows shows the correct, expected behaviour from this permutation of the contents of your character class:
$ echo "a,b\$\$b,c" | sed 's/[^,$]/|/g'
|,|$$|,|
$
It mapped all the non-comma, non-dollar characters to pipes. I should be using single quotes around the echo; then the backslashes wouldn't be necessary. I just followed the question's code quietly.
Following sed may help you in same.
echo "a,b,c" | sed 's/^/|/;s/,/|/g;s/$/|/'
Output will be as follows.
|a|b|c|
I want to replace one string with another but I can't. The code is:
updatedb
MCRYPTINI=$(locate mcrypt.ini | grep 'apache2')
MCRYPTSO=$(locate mcrypt.so | grep "/mcrypt.so")
OLD="extension=mcrypt.so"
NEW="extension=$MCRYPTSO"
echo $MCRYPTINI
echo $MCRYPTSO
echo $OLD
echo $NEW
echo "'s/$OLD/$NEW' $MCRYPTINI"
sed -i 's/$OLD/$NEW' $MCRYPTINI
And the result is:
sudo sh testScript.sh
/etc/php5/apache2/conf.d/20-mcrypt.ini
/usr/lib/php5/20121212/mcrypt.so
extension=mcrypt.so
extension=/usr/lib/php5/20121212/mcrypt.so
's/extension=mcrypt.so/extension=/usr/lib/php5/20121212/mcrypt.so' /etc/php5/apache2/conf.d/20-mcrypt.ini
sed: -e expression #1, char 11: unterminated `s' command
For the response I don't need to use 'sed', but it's looks easy and good.
I use sh not bash because I want the code can use in all the systems, so I prefer answers that follow that principle
UPDATE
sed -i "s/$OLD/$NEW/" $MCRYPTINI
error:
sed: -e expression #1, char 14: unknown option to `s'
Add a slash and double quotes:
sed -i "s/$OLD/$NEW/" file
The solution could be:
sed -i "s/$OLD/$NEW/" $MCRYPTINI
but $NEW is a path, so I need to change "/" by other character, for example "+"
sed -i "s+$OLD+$NEW+" $MCRYPTINI
sed does not print line 1 to line 545.The result of the following command is empty resultfile.txt. Can someone say what should be the correct command?
RESULT=545;sed -n '1, $RESULT p' Configuration.txt > resultfile.txt
The above is not a sed issue, but rather a shell issue: you used single quotes, which inhibit variable expansion.
$ echo '$PWD'
$PWD
$ echo $PWD
/tmp
$ echo "$PWD"
/tmp
Either no quotes at all, or double quotes, allows the shell to expand variables. (No quotes at all means the shell expands everything; double quotes inhibit globbing, redirections, and such.)
Use double quotes so that $RESULT is expanded:
RESULT=545;sed -n "1, $RESULT p" Configuration.txt > resultfile.txt
By the way, the following would be simpler:
head -$RESULT Configuration.txt > resultfile.txt
And, if your file is big, this will quit as soon as you reach line 545 and be more efficient:
sed ${RESULT}q Configuration.txt > resultfile.txt
I have a file like this:
Executing resource: D:\waste2\SPC\depks_rtl_teller_custom.spc
Executing resource: D:\waste2\SPC\ifpks_msg_incoming_cluster.spc
Failed to execute:
Executing resource: D:\waste2\SQL\casapks_batch.sql
Failed to execute:
Executing resource: D:\waste2\SQL\depks_decbatop_kernel.sql
Executing resource: D:\waste2\SQL\depks_services.sql
Failed to execute:
I need a batch file or perl script or ANT script to pick all the lines just in front of the string "Failed to execute:" and copy to a new file. Simply the failed file list I need in a new file. Please assist.
Surprise! The native Windows FINDSTR command can handle this problem quite nicely :-) There is no need for perl, or any other non-native utility.
#echo off
setlocal
::Define LF variable containing a linefeed (0x0A)
set LF=^
::Above 2 blank lines are critical - do not remove
::Define CR variable containing a carriage return (0x0D)
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
setlocal enableDelayedExpansion
::regex "!CR!*!LF!" will match both Unix and Windows style End-Of-Line
findstr /rc:"!CR!*!LF!Failed to execute:" "test.txt" >"failed.txt"
type failed.txt
See What are the undocumented features and limitations of the Windows FINDSTR command? for more info.
With perl, you could do something like:
while(<>) {
print $prev if /^Failed to execute:/;
$prev = $_;
}
To execute directly from your shell, you can use the following command
perl -ne 'print $prev if /^Failed to execute:/; $prev=$_' path/to/your/file
Using tac and sed:
tac file | sed -n '/Failed to execute/{n;p;}' | tac
You could also use two grep invocations, although this is more of a hack (assuming you only have lines starting with either "failed" or "executing"):
grep -B1 '^Failed to execute' your/file | grep '^Executing'
Or
grep -B1 '^Failed to execute' your/file | grep -v '^--' | grep -v '^Failed to execute'
with PowerShell:
PS II> Select-String "Failed to execute:" c:\file.txt -co 1 | % { $_.context.Precontext }
or simply:
for /f "delims=" %%a in (c:\test.txt) do (
echo(%%a| find /i "Failed to execute:" >Nul && (
setlocal enableDelayedExpansion
echo !msg!
endlocal
)
set "msg=%%a"
)