Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace string in the first file it is found

I have a bunch of files named like this:

chapter1.tex
chapter2.tex
chapter3.tex
...
chapter 10.tex
chapter 11.tex
etc.

I am trying to use sed to find and replace the first instance of AAAAAA with ZZZZZZ within all of the files.

sed -i "0,/AAAAAA/s//ZZZZZZ/" chapter*.tex

I tried this above command, but there are two problems:

  1. It finds and replaces the first instance of AAAAAA within each file. I want only the first instance among all files.
  2. I suspect, like many Bash tools, it doesn't properly sort my files in order. E.g. if I type ls then chapter10.tex is listed before chapter1.tex. It is critical it searches the files in order of the chapters.

How to use Bash tools to find and replace first instance, from among a large list of files, so only the first instance in the first found file is replaced, while also respecting the file order (chapter1.tex is first, chapter10.tex is tenth)?

like image 496
Village Avatar asked Apr 24 '26 03:04

Village


2 Answers

With the complete GNU toolchest you don't need a loop.

printf '%s\0' chapter*.tex    \
| sort -zV                    \
| xargs -0 grep -FlZ 'AAAAAA' \
| head -zn1                   \
| xargs -0r sed -i 's/AAAAAA/ZZZZZZ/'
like image 195
oguz ismail Avatar answered Apr 26 '26 18:04

oguz ismail


Here is a bash loop based solution that will work with filenames such as chapter 10.tex i.e. filenames with spaces etc:

while IFS= read -r -d '' file; do
   if grep -q 'AAAAAA' "$file"; then
      echo "changing $file"
      sed -i '0,/AAAAAA/s//ZZZZZZ/' "$file"
      break
   fi
done < <(printf '%s\0' chapter*.tex | sort -z -V)

This is assuming both sed and sort are from gnu utils.


If you have gnu awk 4+ version that supports in-place editing i.e. -i inplace then you can replace grep + sed with single awk:

while IFS= read -r -d '' file; do
   awk -i inplace '!n {n=sub(/AAAAAA/, "ZZZZZZ")} 1;
   END {exit !n}' "$file" && break
done < <(printf '%s\0' chapter*.tex | sort -z -V)
like image 37
anubhava Avatar answered Apr 26 '26 16:04

anubhava