Issue
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:
- It finds and replaces the first instance of
AAAAAA
within each file. I want only the first instance among all files. - I suspect, like many Bash tools, it doesn't properly sort my files in order. E.g. if I type
ls
thenchapter10.tex
is listed beforechapter1.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)?
Solution
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)
Answered By - anubhava Answer Checked By - Dawn Plyler (WPSolving Volunteer)