Här är mitt kommando (bryta avsiktligt):

grep FOO "/Users/gjtorikian/blah" -l | xargs sed -i "" "/FOO/{s/FOO/BAR/g; w /dev/stdout }" 

Högt -nivå: grep för FOO i katalogen blah; rör bara filnamnet (på grund av -l) till sed; sed utför en inline-ersättning (-i "") och skriver ut endast det ändrade ordet till /dev/stdout.

Om jag skulle utelämna -l och rör, jag får tillbaka det från grep:

/Users/gjtorikian/blah/baz.cs:1:FOO /Users/gjtorikian/blah/bar.js:1:FOO 

Vad jag vill ha är sed för att utföra den inbyggda ersättningen och sedan visa mig filen och termen ersatt; till exempel:

/Users/gjtorikian/blah/baz.cs:1:BAR /Users/gjtorikian/blah/bar.js:1:BAR 

Är det möjligt att göra något sådant? Om det betyder något föredrar jag att behålla det bara med grep / sed. Måste jag göra en andra grep efter ?

Kommentarer

  • Jag ser inte ' få det aktuella filnamnet i sed, så du kommer antagligen behöva en andra grep.
  • Du behöver inte ' behöver inte '', att ' är standard.
  • I OS X är '' inte standard .

Svar

En möjlighet skulle vara att skicka utdata från grep till ett separat sed filter.

 grep -l FOO "/Users/gjtorikian/blah/"* | { tee /dev/fd/3 | xargs sed -i -e "/FOO/{" -e "s/FOO/BAR/g" -e "w /dev/stdout" } 3>&1 | sed "s/:FOO$/:BAR/"  

Du kan få sed att skriva ut radnumret (med kommandot =) när det hittar en matchning och göra ytterligare efterbehandling.

Det skulle förmodligen vara tydligare att använda awk.

 for x in "/Users/gjtorikian/blah/"*; do awk " sub(/FOO/, "BAR") {found=1; print FILENAME ":" NR ":" "BAR" >"/dev/stderr"} 1 {print} END {exit(!found)} " "$x" >"$x.tmp" && mv "$x.tmp" "$x" done  

Svar

Som jag ”mn På engelska som modersmål kunde jag nog inte få det.

För att ”grep” en katalog behöver du ”-r”. Användning av ”-l” skriver ut bara filnamn och det slutar greppa efter första inträde.

# pattern=/home ; grep -l "$pattern" /etc/[a-z]* 2>/dev/null | while read line ; do echo "$line:$pattern" ; done /etc/adduser.conf:/home /etc/fstab:/home /etc/fstab~:/home /etc/libuser.conf:/home /etc/mpd.conf:/home /etc/mpd.conf~:/home /etc/mtab:/home /etc/netscsid.conf:/home /etc/passwd:/home /etc/passwd-:/home /etc/sudoers:/home /etc/sudoers.tmp~:/home 

Svar

Jag tror att du gör problemet för komplicerat genom att försöka göra det på en gång. Du kan helt enkelt göra en

grep -H -n /Users/gjtorikian/blah | sed "s/\(^.*?:[0-9]+?:\).*FOO.*/\1BAZ/" 

för att få en lista med filer med radnummer och ersättare (detta ska fungera, så länge dina filnamn inte innehåller kolon, men det är ändå en dålig idé i Mac OS …). Efteråt kan du utfärda en

sed -i "" "s/FOO/BAR/g" /Users/gjtorikian/blah 

Ingen grep och xarg behövs här (du kan göra en ”hitta … | xarg” om du har många filer men). om dubbleringarna kan du placera de två raderna i ett skript eller en funktion och göra variabla utbyten där.

Kommentarer

  • sed -i ... ändrar filtiderna även om strömmen är oförändrad.
  • @jww: du ' har rätt, att ' s eftersom är en strömredigerare och inte en filredigerare, så alternativet -i bryter mot unix-filosofin ( mywiki.wooledge .org / BashFAQ / 021 # Använda_nonstandard_verktyg ). Om du vill undvika det använder du ex (t.ex. ex -sc '%s/FOO/BAR/ge|x' /Users/gjtorikian/blah).

Svar

Ersätt FOO rekursivt med BAR i nuvarande dir (tyst läge)

grep -rl "FOO" | xargs sed -i "s/FOO/BAR/" 

Svar

En liner

grep -n FOO * -R|awk -F\: "{ print $1 }"|sort|uniq|while read file; do sed -i "s/FOO/BAR/g" $file; done 

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *