19

I have n files, like:

file1:

1aaa
2eee

Test        XXX
Hanna
Lars 

file2:

1fff
2ddd
3zzz

Test        XXX
Mike
Charly

I want to remove all rows before "Test XXX" from all n files. The number of rows to delete varies between files.

My idea:

for file in 1 :n
do
pos=grep -n "Test XXX" file$file
sed -i "1:$pos-1 d" file$file >new$file
done
Noah
  • 15,080
  • 13
  • 104
  • 148
Hans
  • 5,345
  • 4
  • 18
  • 10

4 Answers4

28

This should work for you:

sed -i '1,/Test XXX/d' file1
sed -i '1,/Test XXX/d' file2

or simply

sed -i '1,/Test XXX/d' file*
ztank1013
  • 6,939
  • 2
  • 22
  • 20
10

This will work for your examples and even if the matched pattern is on the very first line:

sed -n -E -e '/Text XXX/,$ p' input.txt | sed '1 d'

For example if you input is simply

Test        XXX
Mike
Charly

This will give you

Mike
Charly

If you want to keep the first match Test XXX then just use:

sed -n -E -e '/Text XXX/,$ p' input.txt
Alec Jacobson
  • 6,032
  • 5
  • 51
  • 88
  • 1
    I find a url talking undocument -E (however it seems a ded link; thanks to Google, it has web-storage version). It's eqivalent with -r, which for compatible with BSD ( see the code segment in that dead link page: `/* Undocumented, for compatibility with BSD sed. */ case 'E': case 'r': if (extended_regexp_flags) usage(4); extended_regexp_flags = REG_EXTENDED; break; . . .` – Scott Chu Jun 01 '18 at 03:06
  • That link is sometimes ok, so I'll post its url here: http://blog.dmitryleskov.com/small-hacks/mysterious-gnu-sed-option-e/ – Scott Chu Jun 01 '18 at 03:16
  • From the manual (`man sed`): `-E, -r, --regexp-extended` ; `use extended regular expressions in the script (for portability use POSIX -E).` Also https://www.gnu.org/software/sed/manual/html_node/Extended-regexps.html – Wilf Mar 25 '19 at 22:03
1
cat <<-EOF > file1.txt
1aaa
2eee

Test        XXX
Hanna
Lars
EOF

cat file1.txt | sed -e '/Test *XXX/p' -e '0,/Test *XXX/d'

Output:

Test        XXX
Hanna
Lars

Explanation:

  • -e '/Test *XXX/p' duplicates the line matching /Test *XXX/
  • -e '0,/Test *XXX/d' deletes from line 0 to the first line matching /Test *XXX/

By duplicating the line, then removing the first one, we effectively retain the matched line, successfully deleting all lines BEFORE Test XXX

Note: this will not work as expected if there are multiple Test XXX lines.

Tim Harper
  • 2,561
  • 20
  • 23
1

You can do it with bash ( eg for 1 file)

t=0
while read -r line
do
    [[ $line =~ Test.*XXX ]] && t="1"
    case "$t" in
     1) echo "$line";;
    esac
done < file > tempo && mv tempo file

Use a for loop as necessary to go through all the files

bash-o-logist
  • 6,665
  • 1
  • 17
  • 14