2

In my text file there are many lines whose contents are almost the same. Here are some of them.

So, what I want is to overwrite the / with - on every line and then insert - in front of the line exactly above the line that has the / character overwritten.

Right now I'm trying:

cat text | sed "/\//s/^/- /g;s/\/ /\n- /g"

Input file:

1
00:00:00,000 --> 00:00:00,000
You are older.

2
00:00:00,000 --> 00:00:00,000
By length of a sunset.
/ Is older.

3
00:00:00,000 --> 00:00:00,000
Soona.

4
00:00:00,000 --> 00:00:00,000
Noa!
/ Noa, wait!

Expected output:

1
00:00:00,000 --> 00:00:00,000
You are older.

2
00:00:00,000 --> 00:00:00,000
- By length of a sunset.
- Is older.

3
00:00:00,000 --> 00:00:00,000
Soona.

4
00:00:00,000 --> 00:00:00,000
- Noa!
- Noa, wait!
1
  • 1
    please update the question with a textual description of ... a) the rules for determining which lines to modify and how to modify ... b) the issue(s) with the current code along with the (wrong) output generated by your code
    – markp-fuso
    Commented Jul 8 at 20:07

5 Answers 5

2

I find with this kind of request (do something on the previous line), it's easier to reverse the file, do something on the next line, then re-reverse the file.

tac file | awk 'sub(/^\//, "-") {print; getline; $1 = "- " $1)} 1' | tac

Here, I'm taking advantage of the fact that the sub() function returns the number of substitutions made, which can be treated as a boolean value.


With sed

tac file | sed '/^\// { s//-/; N; s/\n/&- /; }' | tac

This is with the native sed on my Mac. I don't recall if GNU sed complains about the semicolon before the closing brace

1
  • you can install GNU tools with homebrew and use gsed to try
    – phuclv
    Commented Jul 9 at 10:44
1

This might work for you (GNU sed):

sed -E 'N;s/^(- )?(.*\n)\//- \2-/;P;D' file

Open a 2 line window throughout the length of the file.

If the second line begins with a forward slash, replace the forward slash with a dash and insert/(replace a dash followed by a space) with a dash followed by a space.

N.B. This caters for 2 or more lines following the index/time lines.

0

Using GNU sed

$ sed -E 'N;s|([^\n]*\n)/|- \1-|;P;D' input file

or

$ sed -Ez 's|([^\n]*\n)/|- \1-|g' input_file

will both output

1
00:00:00,000 --> 00:00:00,000
You are older.

2
00:00:00,000 --> 00:00:00,000
- By length of a sunset.
- Is older.

3
00:00:00,000 --> 00:00:00,000
Soona.

4
00:00:00,000 --> 00:00:00,000
- Noa!
- Noa, wait!
0

If ed is available/acceptable.

#!/bin/sh

ed -s file.txt <<'EOF'
  g|^/|-s|^|- |\
  +s/^./-/
  ,p
  Q
EOF

Or if an ed script (named script.ed) is desired.

g|^/|-s|^|- |\
+s/^./-/
,p
Q

Then point it against the file (named file.txt) in question.

ed -s file.txt < script.ed

  • Change the ,p to w if you're satisfied with the output and if in-place editing is required.
  • Fails with a large/set of data/files.
0

Another sed variation:

sed 'N; \#\n/# { s//\n-/; s/^/- / }; P;D' input_file
  • N append next line
  • \#\n/# for a pattern space that matches linebreak-slash:
    • s//\n-/ replace linebreak-slash (prior match) with linebreak-dash
    • s/^/- / replace start of pattern space with dash-space
  • P print until newline
  • D delete until newline; restart with resulting pattern space

Not the answer you're looking for? Browse other questions tagged or ask your own question.