bash script search and replace rekursivt
Jeg er løbet lidt i hårdknude, da jeg ikke rigtig ved hvordan jeg kan løse følgende problem:
Jeg skal lave en funktion/command (eller hvad det nu lige hedder) som hhv. kan tage et filnavn eller et mappenavn som parameter. Herefter skal der søges i filen/mappen (rekursivt) efter nogle bestemte strenge (fx top( og footer() og disse skal så erstattes med noget andet (fx intranet_top( og intranet_footer(). Ydermere skal der gerne være noget output der fortæller på hvilke linier i filen/filerne det er ændret og hvad der er ændret.
- Log in to post comments
Kommentarer6
Re: bash script search and replace rekursivt
Uden at kunne komme med en konkret løsning, så kunne det være at sed kan bruges som enten en løsning, eller en del af en løsning.
rekursivt
Jeg ved ikke om det hjælper, dette er en blanding af bash og ruby!
Jeg havde engang brug for at tage delmængden af filerne som lå i to mappe rekursivt.
http://isaksen.biz/ruby/examples/mysubset.rb
Re: bash script search and replace rekursivt
#2 - nah, jeg har ikke mulighed for ruby på den server.. Jeg må holde mig til bash,perl eller python
Jeg tænker om man kunne starte med at bruge grep til at finde de filer der skal rettes i, denne kan jo køres rekursivt (hvis parameteren er et directory), og derefter gemme filnavnene i en midlertidig fil. For så til sidst at kører en løkke for hver linie i den fil, som laver en search and replace.
Lidt ala:
cat > $PWD/file_list | grep -Rs dir
Re: bash script search and replace rekursivt
Hej,
Hvis du kan se bort fra eventruelle stavefejl er her et script der langt hen ad vejen kan det du ønsker.
#!/bin/bash
ARGS=3 # Script kræver 3 argumenter.
ERROR_BADARGS=85 # Fejl kode for manglende argumenter.
ERROR_FILENAME=86 # Fejl kode for forkert eller manglende filnavn
ERROR_NOTEXT=100 # Fejl kode hvis der ikke er tekst der skal byttes i valgt fil
ERROR_CANNOT_CREATE_DIR=101 # Fejlkode hvis midlertidig directory ikke kan oprettes.
SEARCH_TEXT=$1 # Første argument indholder tekst der skal findes
REPLACE_TEXT=$2 # Andet argument indholder tekst der skal udskiftes med
FILE_DIR=$3 # Tredie argument indholder navn på fil elle directory
FILNAVN="" # Bruges til at gemme filnavn der skal rettes. Tildeles værdi senere i script
NOW=`date` # Dato og klokkeslet
script_navn=$(basename $0)
TMP_DIR="/var/tmp/$script_navn$$" # Midlertidig directory til filer
USER=`whoami` # Bruges til at udskrive bruger navn i log fil
SLET_TEMP_DIR="JA" # KUN hvis værdi er lig med JA vil alle midlertidige filer vil blive slettet.
LOG_RES="/home/$USER" # Hvor skal log fil og resultat fil placeres
LOG="$LOG_RES/$script_navn$$.log" # Log over hændelser.
RESULT="$LOG_RES/$script_navn$$.txt" # Resultat log over med rettelser
#++++++++++++++++++++
function Show_Help
{
# Vis en smule hjælp hvis der ikke er 3 argumenter
cat <<- SHOW_HELP
Kald $0 med tekst der skal udskiftes, text der skal indsættes, fil eller directory med filer der skal ændres.
Eksempel: $0 top( intranet_top( /home/script/test
SHOW_HELP
}
#++++++++++++++++++++
function replace_text
{
# Er den tekst der skal erstattes i filen
# Ombøb fil der skal rettes (Laver en backup af filen)
# Find linienummer med tekst der skal byttes og gem det i temp fil.
# Ombyt tekst
# Udskriv forskel på ny og gammel fil
FILNAVN="$1"
mvfilename=$(basename $FILNAVN)
cp $FILNAVN $TMP_DIR/$mvfilename$$
# Gik kopiering godt, ellers fejlmeddelse og stop
if [[ $? -eq 0 ]]; then
echo " $FILNAVN er kopieret til $TMP_DIR/$mvfilename$$">>$LOG
else
# Til LOG fil
echo "Fejl ved oprettelse af $TMP_DIR/$mvfilename$$ script stoppet" >> $LOG
# Til skærm
echo "Fejl ved oprettelse af $TMP_DIR/$mvfilename$$ script stoppet"
exit
fi
# Opret $RESULT hvis den ikke findes.
if [[ ! -f $RESULT ]]; then
result_txt > $RESULT
fi
echo "" >> $RESULT
echo "##### Liste over linienumre og ord der er byttet i $FILNAVN #####" >> $RESULT
# Find linienumre med tekst der skal byttes og gem i $RESULT
grep -n $SEARCH_TEXT $TMP_DIR/$mvfilename$$ >> $RESULT
# Find teksten der skal rettes i backup fil og genopret fil
sed -e "s/$SEARCH_TEXT/$REPLACE_TEXT/g" $TMP_DIR/$mvfilename$$ > $FILNAVN
# Indsæt adskillese mellem oprindelig linienummer:tekst og ny linienummer:tekst
echo "----- Liste over linie numre med nyt ord -----" >> $RESULT
# Indsæt linienummer og tekst i $RESULT
grep -n $REPLACE_TEXT $FILNAVN >> $RESULT
if [[ "$SLET_TEMP_DIR" == "JA" ]] ; then
rm -R $TMP_DIR
if [[ $? -eq 0 ]];then
echo "$TMP_DIR er slettet" >> $LOG
else
echo "Kan ikke slette $TMP_DIR" >> $LOG
fi
fi
}
#++++++++++++++++++++
function result_txt
{
cat <<- RESULT
# Husk at det ord der skal ombyttes til kan findes i forvejen derfor kan der værre flere linier med dette ord.
#
RESULT
}
#++++++++++++++++++++
function create_log
{
# Opret log filnavn
# Log fil bliver kun oprettet hvis der er 3 argumenter
echo "$NOW Startet af $USER" > $LOG
echo " Argumenter: " $SEARCH_TEXT $REPLACE_TEXT $FILE_DIR >> $LOG
}
#++++++++++++++++++++
function find_files
{
if [[ -f "$FILE_DIR" ]]; then
# Argument 3 var et filnavn
# findes den tekst der skal ombyttes eller giv besked og stop
text_exist=$(grep -n "$SEARCH_TEXT" "$FILNAVN")
if [[ $text_exist -gt 0 ]]; then
# tekst til log fil
echo " $SEARCH_TEXT er fundet i $FILE_DIR" >> $LOG
replace_text $FILE_DIR
else
# tekst til log fil
NOW=`date`
echo "$NOW: Kan ikke finde $SEARCH_TEXT i $FILE_DIR" >> $LOG
echo "$NOW: Script stoppet med fejl kode $ERROR_NOTEXT" >> $LOG
# tekst til skærm
echo "$NOW: Kan ikke finde $SEARCH_TEXT i $FILE_DIR"
exit $ERROR_NOTEXT
fi
else
# er argument 3 et directory
if [[ -d "$FILE_DIR" ]]; then
filer=$(grep -rHls $SEARCH_TEXT $FILE_DIR)
# grep --rHls --devices=skip $1 $2
# Lidt om parameterene
# -r Søg recursivt.
# -H Vis filnavn hvor det søgte er fundet.
# -l Stop vidre søgning i filen hvis det søgte er fundet
# -s Vis ikke fejlmeddeleser
# --devices=skip Søg ikke i devices FIFO og sockets
for i in $filer
do
text_exist=$(grep -n "$SEARCH_TEXT" "$i")
if [[ -n "$text_exist" ]]; then
# tekst til log fil
echo " $SEARCH_TEXT er fundet i $i" >> $LOG
replace_text $i
fi
done
else
# tekst til log fil
NOW=`date`
echo "$NOW: Kan ikke finde \"$3\"." >> $LOG
echo "$NOW: Script stoppet med fejl kode $ERROR_FILENAME (Forkert eller manglende filnavn/directory)"
# Tekst til skærm
echo "Kan ikke finde \"$3\"."
exit $ERROR_FILENAME
fi
fi
}
#++++++++++++++++++++
function make_dir
{
if [ ! -d "$1" ] ;then
mkdir $1
if [[ $? -eq 0 ]]; then
NOW=`date`
echo "$NOW: $1 is created" >> $LOG
else
NOW=`date`
echo "$NOW: Kan ikke oprette $1 script stopper" >> $LOG
exit $ERROR_CANNOT_CREATE_DIR
fi
fi
}
#++++++++++++++++++++
# Er der opgiver 3 argumenter, ellers vis hjælp
if [[ $# -ne "$ARGS" ]]; then
Show_Help
exit $ERROR_BADARGS
fi
create_log
make_dir $TMP_DIR
find_files
NOW=`date`
if [[ $? -eq 0 ]]; then
echo "$NOW Normal afslutning af script" >> $LOG
else
echo "$NOW Unormal afslutning af script, fejl ukendt." >> $LOG
fi
Re: bash script search and replace rekursivt
Havde det ikke været fordi du vil have listet filer og linienumre, så kunne du have fået en one liner med sed og find (den i case'en nedenfor) , men så smider vi da bare lidt grep og andet sjov med i posen.
#!/bin/bash
folder=$1
search=`echo ${@:2} | cut -d "/" -f2 | sed 's/" "/"\ "/g'`
replace=`echo ${@:2} | cut -d "/" -f3 | sed 's/" "/"\ "/g'`
grep --color -r "$search" $folder
echo "Replace (y/n)"
read answer
case "$answer" in
y)
sed "s/$search/$replace/" -i `find $folder -type f`
;;
*)
esac
Og den benyttes således
./replace /sti/til/mappe /søge streng på vilkårlig længde/erstatnings streng/
bemærk, der gøres ingen forsøg på at validere argumenterne, ud over at den tillader whitespace uden escape char.
Grep er din ven
#!/bin/bash
match="Det du leder efter"
replacement="Det du erstatter med"
path="Den mappe du leder i"
log="Din log-fil"
pattern="s/$match/$replacement/g"
for i in `grep -rl $match $path`; do
echo `grep -nH $match $i` >> $log
sed -ei $pattern $i # -i = edit in-place
done
http://pasteall.org/3843/bash
Skulle gøre det du vil
Edit: Tegn der kan ødelægge $pattern skal selvfølgeligt escapes - \/, \\, o.l.