volcano
volcano

Reputation: 3582

Conditional replacement of string fragment with sed (one-liner!)

I am trying to process the result of diff operation with sed. This is my diff output, which I pipe into sed

3d2
< 12-03-22_JET_D_CL_UR_l4053_0061 True_Warning All 9 149261 
62a62
> 13-01-29_VUE_EPM3_v37_CSAV2_0370 True_Warning All 13 22125 
68c68
< 13-05-14_Regular_Front_0062 True_Warning All 13 123383 
---
> 13-05-14_Regular_Front_0062 True_Warning All 21 123383 
119c119
< CADS4_PMP363_20130202_DPH_069 True_Warning All 13 233405 
---
> CADS4_PMP363_20130202_DPH_069 True_Warning All 9 233409 
149c149
< CADS4_PMP363_20130315_Fujifilm_UK_186 True_Warning All 21 18611 
---
> CADS4_PMP363_20130315_Fujifilm_UK_186 True_Warning All 17 18615 

I need to sort out the difference string and prepend the 3rd word in the strings with either "Old" or "New" - depending on the first character. My best effort so far is

diff new_jumps/true.jump old_jumps/true.jump | sed -n "/^[<>]/ s:\(.\) \(\S\+\) \(.\+\):\2 \1,\3: p" | replace ">" Old | replace "<" New

Which give me this result (exactly what I wanted).

12-03-22_JET_D_CL_UR_l4053_0061 New,True_Warning All 9 149261 
13-01-29_VUE_EPM3_v37_CSAV2_0370 Old,True_Warning All 13 22125 
13-05-14_Regular_Front_0062 New,True_Warning All 13 123383 
13-05-14_Regular_Front_0062 Old,True_Warning All 21 123383 
CADS4_PMP363_20130202_DPH_069 New,True_Warning All 13 233405 
CADS4_PMP363_20130202_DPH_069 Old,True_Warning All 9 233409 
CADS4_PMP363_20130315_Fujifilm_UK_186 New,True_Warning All 21 18611 
CADS4_PMP363_20130315_Fujifilm_UK_186 Old,True_Warning All 17 18615 

My question is - how can I change conditional expression within sed one-liner that will eliminate the need to use replace afterwards? (I assume that it is possible) Thanks in advance

EDIT:

I know, I missed the option to chain sed expressions, but what I had in mind - is it possible to do it within one substitute operation?

Upvotes: 0

Views: 1728

Answers (4)

Martin
Martin

Reputation: 1

Here is a oneliner for processing spaces in file names necessary to make a cp copy.

The 4 backslashes are necessary so that the final file name is:

<start>\ <end>.<ext>

The script is launched in the shell of a terminal. Its launch is done in a shell. The sed command perhaps launches a shell. Each shell needs an escape backslash, so you need 4 to leave 1 at the end.

Code:

# Escaping special characters from the file name of the file in the consolidation directory of all timestamp files

echo $filename | sed 's/ /\\\\ /g' | (read StandardFilename; echo $StandardFilename)
echo $filenameTimestamp | sed 's/ /\\\\ /g' | (read filenameStandardTimestamp; echo $FilenameStandardTimestamp)
echo "******** Substitution "$Filename " - " $StandardFilename

if cp -Rp $absolutedir/$StandardFilename $2/$StandardTimestampFilename; then
  echo $filename";"$filenameTimestamp";"$YYYY";"$YYMM >> ​​$2/globalExifDataFormattee.csv;
  let "cptFilesCopies += 1"
else
  echo "ERROR copying "$absolutedir"/$filename to "$2"/$filenameTimestamp" >> $logname;
  let "cptFileErrors += 1"; let "cptLocalErrors += 1";
fi

Upvotes: -1

jaybee
jaybee

Reputation: 955

@volcano: here is a one-liner solution in sed, but relies in the interaction with the shell. IMHO if you want to have only one sed substitution command, you cannot avoid that behavior: you have to output to the shell the information of which first character has been seen on the line, the shell somewhat does the mapping to "Old" or "New" strings, and gives the result back to sed.

So the one-liner is not exactly a one-liner because we have to define things in the shell... ;)

replace() { if [ "$1" == ">" ] ; then echo -n "Old"; else echo -n "New" ; fi }
export -f replace
sed -n '/^[<>]/ s:\(.\) \(\S\+\) \(.\+\):echo "\2 $(replace \\\1),\3";:ep' yourfile

Please note that the e flag to the substitution command is a GNU sed extension, we use it here to avoid calling the shell explicitly. If you don't use GNU sed, you can simply replace the last line above by the following:

sed -n '/^[<>]/ s:\(.\) \(\S\+\) \(.\+\):echo "\2 $(replace \\\1),\3";:p' yourfile | bash

The solution I am giving here has been inspired by that other one.

Please also note that all this gymnastics is avoidable if you accept to replace your three-letter tokens "Old" and "New" by their initials, because then we can neatly use the y command to first act in a tr fashion, likewise:

sed -n '/^[<>]/ y/<>/ON/; s:\(.\) \(\S\+\) \(.\+\):\2 \1,\3:p' yourfile

Upvotes: 0

condorwasabi
condorwasabi

Reputation: 626

With awk I get a faster response. Try this:

diff new_jumps/true.jump old_jumps/true.jump | awk '{ if($1=="<" || $1==">"){($1=="<")?temp="New,":temp="Old,";print $2,temp$3,$4,$5}}'

Here's another solution suggested by Jidder:

awk '/^</{i="old,"}/^>/{i="new,"}i{$2=$2" "i;print;i=0}'

Upvotes: 1

Arnestig
Arnestig

Reputation: 2340

By adding more commands to sed using semicolon (;), like this:

diff new_jumps/true.jump old_jumps/true.jump | sed -n "/^[<>]/ s:\(.\) \(\S\+\) \(.\+\):\2 \1,\3:; s/</New/gp; s/>/Old/gp"

Upvotes: 2

Related Questions