Risposte:
cd /path/to/your/folder
sed -i 's/foo/bar/g' *
Le occorrenze di "foo" saranno sostituite da "bar".
Su sistemi BSD come macOS, è necessario fornire un'estensione di backup come -i '.bak'
"corruzione del rischio o contenuto parziale" per ogni pagina di manuale.
cd /path/to/your/folder
sed -i '.bak' 's/foo/bar/g' *
sed
, -i
richiede una stringa dopo di essa, che viene aggiunta ai vecchi nomi di file. Quindi sed -i .bak 's/foo/bar/g' *.xx
sposta tutti i .xx
file sul .xx.bak
nome equivalente e quindi genera i .xx
file con la sostituzione foo → bar.
sed -i 's/foo\ with\ spaces/bar/g' *
. Suppongo che tu l'abbia scoperto dopo così tanto tempo ... ma in questo modo rimane per gli altri trovare lo stesso problema.
sed -i -e 's/foo/bar/g' $(find /home/user/base/dir)
Simile alla risposta di Kaspar ma con la bandiera g per sostituire tutte le occorrenze su una riga.
find ./ -type f -exec sed -i 's/string1/string2/g' {} \;
Per maiuscole e minuscole globali:
find ./ -type f -exec sed -i 's/string1/string2/gI' {} \;
LC_ALL=C find ./ -type f -exec sed -i '' -e 's/proc.priv/priv/g' {} \;
(vedi questo post e questo )
--include=*.whatever
con -r
.git/
. Assicurati di cd
scendere a un livello inferiore.
git status
ritorni: error: bad index file sha1 signature.... fatal: index file corrupt
. Cosa dà?
La risposta di @ kev è buona, ma riguarda solo i file nella directory immediata. L'esempio seguente utilizza grep per trovare ricorsivamente i file. Funziona per me ogni volta.
grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
Ripartizione del comando
grep -r : --recursive , legge in modo ricorsivo tutti i file in ciascuna directory.
grep -l : --print-with-match , stampa il nome di ogni file che ha una corrispondenza, invece di stampare le linee corrispondenti.
grep -i : --ignore-case .
xargs : trasforma STDIN in argomenti, segui questa risposta .
Il comando xargs -i @ ~ contiene @ ~ : un segnaposto per l'argomento da utilizzare in una posizione specifica nel comando ~ , il segno @ è un segnaposto che può essere sostituito da qualsiasi stringa.
sed -i : modifica i file in atto, senza backup.
sed s / regexp / sostituzione / : sostituisce regexp di corrispondenza della stringa con sostituzione .
sed s / regexp / sostituzione / g : globale , effettua la sostituzione per ogni incontro anziché solo il primo incontro.
grep --include={*.php,*.html,*.js} -rnl './' -e "old-word" | xargs -i@ sed -i 's/old-word/new-word/g' @
|
, anche perché -i
nel comando xargs? Ho letto nel manuale che è deprecato e dovrebbe usare -I
invece. E viene @
utilizzato come delimitatore per l'inizio e la fine del modello?
grep -rli 'old-word' * | xargs -I@ sed -i '' 's/2.0.0/latest/g' @
rli
@
Questo ha funzionato per me:
find ./ -type f -exec sed -i 's/string1/string2/' {} \;
Howerver, questo non ha fatto: sed -i 's/string1/string2/g' *
. Forse "pippo" non doveva essere stringa1 e "barra" non stringa2.
find ./ -type f -exec sed -i '' -e 's/string1/string2/' {} \;
Ci sono alcune risposte standard a questo già elencato. In generale, è possibile utilizzare find per elencare in modo ricorsivo i file e quindi eseguire le operazioni con sed o perl .
Per gli usi più rapidi, potresti trovare il comando rpl molto più facile da ricordare. Ecco la sostituzione (foo -> bar), ricorsivamente su tutti i file:
rpl -R foo bar .
Probabilmente dovrai installarlo ( apt-get install rpl
o simile).
Tuttavia, per i lavori più difficili che coinvolgono espressioni regolari e sostituzione sostitutiva, o rinominazioni di file e ricerca e sostituzione, lo strumento più generale e potente di cui sono a conoscenza è repren , un piccolo script Python che ho scritto qualche tempo fa per alcuni compiti di rinominazione e refactoring più spinosi. I motivi che potresti preferire sono:
Per usarlo, pip install repren
. Controlla il README per esempi.
Per sostituire una stringa in più file è possibile utilizzare:
grep -rl string1 somedir/ | xargs sed -i 's/string1/string2/g'
Per esempio
grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'
Per sostituire un percorso all'interno dei file (evitando i caratteri di escape) è possibile utilizzare il comando seguente:
sed -i 's@old_path@new_path@g'
Il segno @ indica che tutti i caratteri speciali devono essere ignorati in una stringa seguente.
Nel caso in cui la tua stringa abbia una barra (/), puoi cambiare il delimitatore in '+'.
find . -type f -exec sed -i 's+http://example.com+https://example.com+g' {} +
Questo comando verrebbe eseguito in modo ricorsivo nella directory corrente.
../domain.com
adomain.com
Le occorrenze della prima riga di "pippo" verranno sostituite con "barra". E puoi usare la seconda riga per controllare.
grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
grep 'foo' -r * | awk -F: {'print $1'} | sort -n | uniq -c
grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
Se hai un elenco di file che puoi usare
replace "old_string" "new_string" -- file_name1 file_name2 file_name3
Se hai tutti i file che puoi usare
replace "old_string" "new_string" -- *
Se si dispone di un elenco di file con estensione, è possibile utilizzare
replace "old_string" "new_string" -- *.extension
replace "old_string" "new_string" -- *.txt
replace
utility. Senza queste informazioni, questa risposta è incompleta.
"Puoi anche usare find e sed, ma trovo che questa piccola riga di perl funzioni bene.
perl -pi -w -e 's/search/replace/g;' *.php
"(Estratto da http://www.liamdelahunty.com/tips/linux_search_and_replace_multiple_files.php )
I miei migliori risultati provengono dall'uso di perl e grep (per garantire che il file abbia l'espressione di ricerca)
perl -pi -w -e 's/search/replace/g;' $( grep -rl 'search' )
Dato che vuoi cercare la stringa search
e sostituirla con replace
più file, questa è la mia formula a riga singola testata in battaglia :
grep -RiIl 'search' | xargs sed -i 's/search/replace/g'
Spiegazione rapida grep:
-R
- ricerca ricorsiva-i
- senza distinzione tra maiuscole e minuscole-I
- salta i file binari (vuoi testo, giusto?)-l
- stampa un semplice elenco come output. Necessario per gli altri comandiL'output grep viene quindi reindirizzato a sed (tramite xargs) che viene effettivamente utilizzato per sostituire il testo. Il -i
flag modificherà direttamente il file. Rimuoverlo per una sorta di modalità "marcia a secco".
Ho inventato la mia soluzione prima di trovare questa domanda (e risposte). Ho cercato diverse combinazioni di "sostituire" "diversi" e "xml", perché quella era la mia applicazione, ma non ho trovato questo particolare.
Il mio problema: avevo file XML primavera con dati per casi di test, contenenti oggetti complessi. Un refactor sul codice sorgente Java ha cambiato molte classi e non si applicava ai file di dati XML. Per salvare i dati dei casi di test, avevo bisogno di cambiare tutti i nomi delle classi in tutti i file xml, distribuiti su più directory. Tutto mentre salvavo le copie di backup dei file xml originali (anche se questo non era un must, poiché il controllo della versione mi avrebbe salvato qui).
Stavo cercando una combinazione di find
+ sed
, perché ha funzionato per me in altre situazioni, ma non con più sostituzioni contemporaneamente.
Poi ho trovato chiedere la risposta a Ubuntu e mi ha aiutato a costruire la mia riga di comando:
find -name "*.xml" -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;
E ha funzionato perfettamente (bene, il mio caso ha avuto sei diversi sostituti). Ma tieni presente che toccherà tutti i file * .xml nella directory corrente. Per questo motivo, e se sei responsabile nei confronti di un sistema di controllo della versione, potresti voler prima filtrare e passare solo a sed
quelli che hanno effettivamente le stringhe che desideri; piace:
find -name "*.xml" -exec grep -e "firstWord" -e "secondWord" -e "thirdWord" {} \; -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;
findstr /spin /c:"quéquieresbuscar" *.xml
sarà utile.
Davvero zoppo, ma non sono riuscito a far funzionare nessuno dei comandi sed su OSX, quindi ho fatto invece questa cosa stupida:
:%s/foo/bar/g
:wn
^ - copia queste tre righe negli appunti (sì, includi la riga finale), quindi:
vi *
e tieni premuto command-v fino a quando non dice che non ci sono più file.
Dumb ... hacky ... efficace ...
Su un MacBook Pro, ho usato quanto segue (ispirato a https://stackoverflow.com/a/19457213/6169225 ):
sed -i '' -e 's/<STR_TO_REPLACE>/<REPLACEMENT_STR>/g' *
-i ''
assicurerà che non si eseguano backup.
-e
per regex moderno.
-e
dice a sed che il prossimo token è un comando. Per espressioni regolari estese, utilizzare -E
invece.
L'editor di flusso modifica più file "inplace" quando viene richiamato con l'opzione -i
, che accetta un file di backup che termina come argomento. Così
sed -i.bak 's/foo/bar/g' *
sostituisce foo
con bar
in tutti i file in questa cartella, ma non scende nelle sottocartelle. Questo genererà comunque un nuovo .bak
file per ogni file nella tua directory. Per fare questo in modo ricorsivo per tutti i file in questa directory e tutte le sue sottodirectory, è necessario un aiuto, come find
, per attraversare l'albero delle directory.
find ./ -print0 | xargs -0 sed -i.bak 's/foo/bar/g' *
find
consente ulteriori restrizioni su quali file modificare, specificando ulteriori argomenti come find ./ -name '*.php' -or -name '*.html' -print0
, se necessario.
Nota: GNU sed
non richiede la fine di un file, sed -i 's/foo/bar/g' *
funzionerà anche; FreeBSD sed
richiede un'estensione, ma consente uno spazio in mezzo, quindi sed -i .bak s/foo/bar/g *
funziona.
script per comando multiedito
multiedit [-n PATTERN] OLDSTRING NEWSTRING
Dalla risposta di Kaspar ho creato uno script bash per accettare gli argomenti della riga di comando e, facoltativamente, limitare i nomi dei file che corrispondono a un modello. Salva nel tuo $ PATH e rendilo eseguibile, quindi usa semplicemente il comando sopra.
Ecco la sceneggiatura:
#!/bin/bash
_help="\n
Replace OLDSTRING with NEWSTRING recursively starting from current directory\n
multiedit [-n PATTERN] OLDSTRING NEWSTRING\n
[-n PATTERN] option limits to filenames matching PATTERN\n
Note: backslash escape special characters\n
Note: enclose STRINGS with spaces in double quotes\n
Example to limit the edit to python files:\n
multiedit -n \*.py \"OLD STRING\" NEWSTRING\n"
# ensure correct number of arguments, otherwise display help...
if [ $# -lt 2 ] || [ $# -gt 4 ]; then echo -e $_help ; exit ; fi
if [ $1 == "-n" ]; then # if -n option is given:
# replace OLDSTRING with NEWSTRING recursively in files matching PATTERN
find ./ -type f -name "$2" -exec sed -i "s/$3/$4/g" {} \;
else
# replace OLDSTRING with NEWSTRING recursively in all files
find ./ -type f -exec sed -i "s/$1/$2/" {} \;
fi
Se il file contiene barre rovesciate (in genere i percorsi) puoi provare qualcosa del genere:
sed -i -- 's,<path1>,<path2>,g' *
ex:
sed -i -- 's,/foo/bar,/new/foo/bar,g' *.sh (in all shell scripts available)
Per mantenere il mio nodo inglese personale, ho scritto uno script di utilità che aiuta a sostituire più coppie di stringhe vecchie / nuove, per tutti i file in una directory ricorsivamente.
Le coppie multiple di stringhe vecchie / nuove sono gestite in una mappa hash.
La directory può essere impostata tramite riga di comando o variabile di ambiente, la mappa è codificata nello script, ma è possibile modificare il codice da caricare da un file, se necessario.
Richiede bash 4.2, a causa di alcune nuove funzionalità.
en_standardize.sh:
#! /bin/bash
# (need bash 4.2+,)
#
# Standardize phonetic symbol of English.
#
# format:
# en_standardize.sh [<dir>]
#
# params:
# * dir
# target dir, optional,
# if not specified then use environment variable "$node_dir_en",
# if both not provided, then will not execute,
# *
#
paramCount=$#
# figure target dir,
if [ $paramCount -ge 1 ]; then # dir specified
echo -e "dir specified (in command):\n\t$1\n"
targetDir=$1
elif [[ -v node_dir_en ]]; then # environable set,
echo -e "dir specified (in environment vairable):\n\t$node_dir_en\n"
targetDir=$node_dir_en
else # environable not set,
echo "dir not specified, won't execute"
exit
fi
# check whether dir exists,
if [ -d $targetDir ]; then
cd $targetDir
else
echo -e "invalid dir location:\n\t$targetDir\n"
exit
fi
# initial map,
declare -A itemMap
itemMap=( ["ɪ"]="i" ["ː"]=":" ["ɜ"]="ə" ["ɒ"]="ɔ" ["ʊ"]="u" ["ɛ"]="e")
# print item maps,
echo 'maps:'
for key in "${!itemMap[@]}"; do
echo -e "\t$key\t->\t${itemMap[$key]}"
done
echo -e '\n'
# do replace,
for key in "${!itemMap[@]}"; do
grep -rli "$key" * | xargs -i@ sed -i "s/$key/${itemMap[$key]}/g" @
done
echo -e "\nDone."
exit
L'uso del comando ack sarebbe molto più veloce in questo modo:
ack '25 Essex' -l | xargs sed -i 's/The\ fox \jump/abc 321/g'
Anche se hai uno spazio bianco nel risultato della ricerca. Devi scappare.
Sto dando un esempio per correggere un errore shebang comune nelle fonti Python.
Puoi provare l'approccio grep / sed. Eccone uno che funziona con GNU sed e non romperà un repository git:
$ grep -rli --exclude '*.git*' '#!/usr/bin/python' . | xargs -I {} \
gsed -i '' -e 's/#!\/usr\/bin\/python/#!\/usr\/bin\/env python/' {}
Oppure puoi usare greptile :)
$ greptile -x .py -l -i -g '#!/usr/bin/env python' -r '#!/usr/bin/python' .
Ho appena testato il primo script e anche il secondo dovrebbe funzionare. Fai attenzione ai personaggi di escape, penso che dovrebbe essere più facile usare greptile nella maggior parte dei casi. Certo, puoi fare molte cose interessanti con sed, e per questo potrebbe essere preferibile padroneggiarlo usandolo con xargs.
L'ho trovato da un altro post (non ricordo quale) e sebbene non sia il più elegante, è semplice e come utente Linux alle prime armi non mi ha dato problemi
for i in *old_str* ; do mv -v "$i" "${i/\old_str/new_str}" ; done
se hai spazi o altri caratteri speciali usa un \
for i in *old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done
per le stringhe nelle sottodirectory usare **
for i in *\*old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done
Esiste un modo più semplice utilizzando un semplice file di script:
# sudo chmod +x /bin/replace_string_files_present_dir
apri il file in gedit o in un editor a tua scelta, io uso gedit qui.
# sudo gedit /bin/replace_string_files_present_dir
Quindi nell'editor incolla quanto segue nel file
#!/bin/bash
replace "oldstring" "newstring" -- *
replace "oldstring1" "newstring2" -- *
#add as many lines of replace as there are your strings to be replaced for
#example here i have two sets of strings to replace which are oldstring and
#oldstring1 so I use two replace lines.
Salva il file, chiudi gedit , quindi chiudere il terminale o semplicemente chiuderlo e quindi avviarlo per poter caricare il nuovo script aggiunto.
Passare alla directory in cui sono presenti più file che si desidera modificare. Quindi eseguire:
#replace_string_files_present_dir
Premi Invio e questo sostituirà automaticamente oldstring e oldstring1 in tutti i file che li contengono rispettivamente con il newstring e il newstring1 corretti .
Salterà tutte le directory e i file che non contengono le vecchie stringhe.
Questo potrebbe aiutare ad eliminare il noioso lavoro di digitazione nel caso in cui tu abbia più directory con file che richiedono la sostituzione di stringhe. Tutto quello che devi fare è accedere a ciascuna di quelle directory, quindi eseguire:
#replace_string_files_present_dir
Tutto quello che devi fare è assicurarti di aver incluso o aggiunto tutte le stringhe di sostituzione come ti ho mostrato sopra:
replace "oldstring" "newstring" -- *
alla fine del file / bin / replace_string_files_present_dir .
Per aggiungere una nuova stringa di sostituzione basta aprire lo script che abbiamo creato digitando quanto segue nel terminale:
sudo gedit /bin/replace_string_files_present_dir
Non preoccuparti del numero di stringhe di sostituzione che aggiungi, non avranno alcun effetto se la stringa vecchia non viene trovata.
.gitlab-ci.yml
o a travis.yml
). Ogni giro consistente nello scrivere uno script per eseguirlo in un secondo momento è un anti-pattern, perché dovrai quindi creare script per la creazione dello script (e io
$ sostituisci "Da" "A" - `trova / percorso / a / cartella -tipo f`
(sostituisci - un'utilità di sostituzione delle stringhe del sistema di database MySQL)