Câu trả lời:
cd /path/to/your/folder
sed -i 's/foo/bar/g' *
Sự xuất hiện của "foo" sẽ được thay thế bằng "thanh".
Trên các hệ thống BSD như macOS, bạn cần cung cấp tiện ích mở rộng sao lưu như -i '.bak'
"rủi ro tham nhũng hoặc nội dung một phần" trên mỗi trang.
cd /path/to/your/folder
sed -i '.bak' 's/foo/bar/g' *
sed
, -i
yêu cầu một chuỗi sau nó, được gắn vào tên tệp cũ. Vì vậy, sed -i .bak 's/foo/bar/g' *.xx
di chuyển tất cả .xx
các tệp sang .xx.bak
tên tương đương và sau đó tạo các .xx
tệp với sự thay thế thanh foo →.
sed -i 's/foo\ with\ spaces/bar/g' *
. Tôi cho rằng bạn đã phát hiện ra sau một thời gian dài ... nhưng cách này vẫn giúp người khác tìm ra vấn đề tương tự.
sed -i -e 's/foo/bar/g' $(find /home/user/base/dir)
Tương tự như câu trả lời của Kaspar nhưng với cờ g để thay thế tất cả các lần xuất hiện trên một dòng.
find ./ -type f -exec sed -i 's/string1/string2/g' {} \;
Đối với trường hợp toàn cầu không nhạy cảm:
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' {} \;
(xem bài đăng này và bài này )
--include=*.whatever
bằng -r
.git/
. Hãy chắc chắn để cd
xuống mức thấp hơn.
git status
trở lại : error: bad index file sha1 signature.... fatal: index file corrupt
. Đưa cái gì?
Câu trả lời của @ kev là tốt, nhưng chỉ ảnh hưởng đến các tệp trong thư mục ngay lập tức. Ví dụ bên dưới sử dụng grep để tìm đệ quy các tệp. Nó làm việc cho tôi mọi lúc.
grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
Sự cố lệnh
grep -r : --recursive , đọc đệ quy tất cả các tệp trong mỗi thư mục.
grep -l : --print-with-match , in tên của từng tệp có khớp, thay vì in các dòng khớp.
grep -i : - trường hợp khác .
xargs : biến đổi STDIN thành đối số, làm theo câu trả lời này .
Lệnh xargs -i @ ~ chứa @ ~ : một trình giữ chỗ cho đối số được sử dụng ở một vị trí cụ thể trong lệnh ~ ~ , dấu @ là một trình giữ chỗ có thể được thay thế bằng bất kỳ chuỗi nào.
sed -i : chỉnh sửa tập tin tại chỗ, không cần sao lưu.
sed s / regapi / thay thế / : chuỗi thay thế phù hợp với regrec với thay thế .
sed s / regapi / thay thế / g : toàn cầu , thực hiện thay thế cho mỗi trận đấu thay vì chỉ trận đấu đầu tiên.
grep --include={*.php,*.html,*.js} -rnl './' -e "old-word" | xargs -i@ sed -i 's/old-word/new-word/g' @
|
, tại sao -i
trong lệnh xargs? Tôi đọc trong hướng dẫn sử dụng nó không được dùng nữa và nên sử dụng -I
thay thế. Và được @
sử dụng như một dấu phân cách cho bắt đầu và kết thúc cho mẫu?
grep -rli 'old-word' * | xargs -I@ sed -i '' 's/2.0.0/latest/g' @
rli
) và @
ví dụ về dấu hiệu
Điều này làm việc cho tôi:
find ./ -type f -exec sed -i 's/string1/string2/' {} \;
Howerver, điều này đã không : sed -i 's/string1/string2/g' *
. Có lẽ "foo" không có nghĩa là chuỗi1 và "thanh" không phải là chuỗi2.
find ./ -type f -exec sed -i '' -e 's/string1/string2/' {} \;
Có một vài câu trả lời tiêu chuẩn cho điều này đã được liệt kê. Nói chung, bạn có thể sử dụng find để liệt kê đệ quy các tệp và sau đó thực hiện các thao tác với sed hoặc perl .
Đối với hầu hết các sử dụng nhanh chóng, bạn có thể thấy lệnh rpl dễ nhớ hơn nhiều. Đây là sự thay thế (foo -> bar), đệ quy trên tất cả các tệp:
rpl -R foo bar .
Có lẽ bạn sẽ cần phải cài đặt nó (apt-get install rpl
hoặc tương tự).
Tuy nhiên, đối với các công việc khó khăn hơn liên quan đến biểu thức chính quy và thay thế trở lại, hoặc đổi tên tệp cũng như tìm kiếm và thay thế, công cụ mạnh mẽ và tổng quát nhất mà tôi biết là repren , một đoạn mã Python nhỏ mà tôi đã viết trước đây cho một số đổi tên và tái cấu trúc nhiệm vụ. Những lý do bạn có thể thích nó là:
Để sử dụng nó , pip install repren
. Kiểm tra README cho ví dụ.
Để thay thế một chuỗi trong nhiều tệp, bạn có thể sử dụng:
grep -rl string1 somedir/ | xargs sed -i 's/string1/string2/g'
Ví dụ
grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'
Để thay thế một đường dẫn trong tệp (tránh các ký tự thoát), bạn có thể sử dụng lệnh sau:
sed -i 's@old_path@new_path@g'
Dấu @ có nghĩa là tất cả các ký tự đặc biệt sẽ bị bỏ qua trong một chuỗi sau.
Trong trường hợp chuỗi của bạn có dấu gạch chéo (/) trong đó, bạn có thể thay đổi dấu phân cách thành '+'.
find . -type f -exec sed -i 's+http://example.com+https://example.com+g' {} +
Lệnh này sẽ chạy đệ quy trong thư mục hiện tại.
../domain.com
đểdomain.com
Sự xuất hiện dòng đầu tiên của "foo" sẽ được thay thế bằng "thanh". Và bạn có thể sử dụng dòng thứ hai để kiểm tra.
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'
Nếu bạn có danh sách các tập tin bạn có thể sử dụng
replace "old_string" "new_string" -- file_name1 file_name2 file_name3
Nếu bạn có tất cả các tập tin bạn có thể sử dụng
replace "old_string" "new_string" -- *
Nếu bạn có danh sách các tệp có phần mở rộng, bạn có thể sử dụng
replace "old_string" "new_string" -- *.extension
replace "old_string" "new_string" -- *.txt
replace
tiện ích này . Không có thông tin này, câu trả lời này là không đầy đủ.
"Bạn cũng có thể sử dụng find và sed, nhưng tôi thấy rằng dòng perl nhỏ này hoạt động độc đáo.
perl -pi -w -e 's/search/replace/g;' *.php
"(Trích xuất từ http: // www. Nghịdelahunty.com / tip / linux_search_and_Vplace_mult Môn_files.php )
Kết quả tốt nhất của tôi đến từ việc sử dụng perl và grep (để đảm bảo rằng tệp có biểu thức tìm kiếm)
perl -pi -w -e 's/search/replace/g;' $( grep -rl 'search' )
Cho rằng bạn muốn tìm kiếm chuỗi search
và thay thế nó bằng replace
nhiều tệp, đây là công thức một dòng được thử nghiệm trong trận chiến của tôi :
grep -RiIl 'search' | xargs sed -i 's/search/replace/g'
Giải thích nhanh về grep:
-R
- tìm kiếm đệ quy-i
- trường hợp không nhạy cảm-I
- bỏ qua các tệp nhị phân (bạn muốn văn bản, phải không?)-l
- in một danh sách đơn giản như đầu ra. Cần thiết cho các lệnh khácĐầu ra grep sau đó được chuyển sang sed (thông qua xargs) được sử dụng để thực sự thay thế văn bản. Các -i
lá cờ sẽ làm thay đổi các tập tin trực tiếp. Hủy bỏ nó cho một loại chế độ "chạy khô".
Tôi đã tự pha chế giải pháp của riêng mình trước khi tôi tìm thấy câu hỏi này (và câu trả lời). Tôi đã tìm kiếm các kết hợp khác nhau của "thay thế" "vài" và "xml", vì đó là ứng dụng của tôi, nhưng không tìm thấy kết hợp cụ thể này.
Vấn đề của tôi: Tôi đã có các tệp xml mùa xuân với dữ liệu cho các trường hợp thử nghiệm, có chứa các đối tượng phức tạp. Một bộ cấu trúc lại mã nguồn java đã thay đổi rất nhiều lớp và không áp dụng cho các tệp dữ liệu xml. Để lưu dữ liệu trường hợp thử nghiệm, tôi cần thay đổi tất cả các tên lớp trong tất cả các tệp xml, được phân phối trên một số thư mục. Tất cả trong khi lưu các bản sao lưu của các tệp xml gốc (mặc dù điều này không bắt buộc, vì kiểm soát phiên bản sẽ lưu tôi ở đây).
Tôi đã tìm kiếm một số kết hợp find
+ sed
, bởi vì nó hoạt động cho tôi trong các tình huống khác, nhưng không phải với một vài sự thay thế cùng một lúc.
Sau đó, tôi tìm thấy câu hỏi ubfox và nó đã giúp tôi xây dựng dòng lệnh của mình:
find -name "*.xml" -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;
Và nó hoạt động hoàn hảo (tốt, trường hợp của tôi có sáu lần thay thế khác nhau). Nhưng xin lưu ý rằng nó sẽ chạm vào tất cả các tệp * .xml trong thư mục hiện tại. Do đó, và nếu bạn chịu trách nhiệm với hệ thống kiểm soát phiên bản, bạn có thể muốn lọc trước và chỉ truyền cho sed
những người thực sự có chuỗi bạn muốn; giống:
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
Nó sẽ rất hữu ích.
Thực sự khập khiễng, nhưng tôi không thể có bất kỳ lệnh sed nào hoạt động ngay trên OSX, vì vậy tôi đã làm điều ngu ngốc này thay vào đó:
:%s/foo/bar/g
:wn
^ - sao chép ba dòng này vào bảng tạm của tôi (có, bao gồm dòng mới kết thúc), sau đó:
vi *
và giữ lệnh-v cho đến khi nó nói không còn tệp nào.
Câm ... hacky ... hiệu quả ...
Trên MacBook Pro, tôi đã sử dụng như sau (lấy cảm hứng từ https://stackoverflow.com/a/19457213/6169225 ):
sed -i '' -e 's/<STR_TO_REPLACE>/<REPLACEMENT_STR>/g' *
-i ''
sẽ đảm bảo bạn không lấy bản sao lưu.
-e
cho regex hiện đại.
-e
chỉ nói với sed rằng mã thông báo tiếp theo là một lệnh. Đối với các biểu thức chính quy mở rộng, sử dụng -E
thay thế.
Trình chỉnh sửa luồng thực hiện sửa đổi nhiều tập tin -i
, trong đó có một tập tin trực tuyến, khi được gọi bằng khóa chuyển, sẽ lấy một tập tin sao lưu kết thúc làm đối số. Vì thế
sed -i.bak 's/foo/bar/g' *
thay thế foo
bằng bar
trong tất cả các tệp trong thư mục này, nhưng không hạ xuống thành các thư mục con. Tuy nhiên, điều này sẽ tạo ra một .bak
tệp mới cho mọi tệp trong thư mục của bạn. Để thực hiện điều này một cách đệ quy cho tất cả các tệp trong thư mục này và tất cả các thư mục con của nó, bạn cần một người trợ giúp, như find
, để duyệt qua cây thư mục.
find ./ -print0 | xargs -0 sed -i.bak 's/foo/bar/g' *
find
cho phép bạn hạn chế thêm về những tệp cần sửa đổi, bằng cách chỉ định thêm các đối số như find ./ -name '*.php' -or -name '*.html' -print0
, nếu cần.
Lưu ý: GNU sed
không yêu cầu một tệp kết thúc, sed -i 's/foo/bar/g' *
cũng sẽ hoạt động; FreeBSD sed
yêu cầu một phần mở rộng, nhưng cho phép một không gian ở giữa, vì vậy sed -i .bak s/foo/bar/g *
hoạt động.
tập lệnh cho lệnh multiedit
multiedit [-n PATTERN] OLDSTRING NEWSTRING
Từ câu trả lời của Kaspar, tôi đã tạo một tập lệnh bash để chấp nhận các đối số dòng lệnh và tùy ý giới hạn tên tệp khớp với một mẫu. Tiết kiệm trong $ PATH của bạn và thực hiện, sau đó chỉ cần sử dụng lệnh ở trên.
Đây là kịch bản:
#!/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
Nếu tệp chứa dấu gạch chéo ngược (đường dẫn thường), bạn có thể thử một cái gì đó như thế này:
sed -i -- 's,<path1>,<path2>,g' *
Ví dụ:
sed -i -- 's,/foo/bar,/new/foo/bar,g' *.sh (in all shell scripts available)
Để duy trì nút tiếng Anh cá nhân của mình, tôi đã viết một tập lệnh tiện ích giúp thay thế nhiều cặp chuỗi cũ / mới, cho tất cả các tệp trong một thư mục theo cách đệ quy.
Nhiều cặp chuỗi cũ / mới được quản lý trong bản đồ băm.
Có thể đặt dir thông qua dòng lệnh hoặc biến môi trường, bản đồ được mã hóa cứng trong tập lệnh, nhưng bạn có thể sửa đổi mã để tải từ tệp, nếu cần.
Nó yêu cầu bash 4.2, do một số tính năng mới.
en_st Chuẩn hóa.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
Sử dụng lệnh ack sẽ nhanh hơn rất nhiều như thế này:
ack '25 Essex' -l | xargs sed -i 's/The\ fox \jump/abc 321/g'
Ngoài ra nếu bạn có một khoảng trắng trong kết quả tìm kiếm. Bạn cần phải thoát khỏi nó.
Tôi đang đưa ra một ví dụ để sửa một lỗi shebang phổ biến trong các nguồn python.
Bạn có thể thử phương pháp grep / sed. Đây là một cái hoạt động với GNU sed và sẽ không phá vỡ một repo git:
$ grep -rli --exclude '*.git*' '#!/usr/bin/python' . | xargs -I {} \
gsed -i '' -e 's/#!\/usr\/bin\/python/#!\/usr\/bin\/env python/' {}
Hoặc bạn có thể sử dụng greptile :)
$ greptile -x .py -l -i -g '#!/usr/bin/env python' -r '#!/usr/bin/python' .
Tôi vừa thử nghiệm kịch bản đầu tiên, và kịch bản thứ hai cũng hoạt động tốt. Hãy cẩn thận với các ký tự thoát, tôi nghĩ rằng nó sẽ dễ sử dụng greptile hơn trong hầu hết các trường hợp. Tất nhiên, bạn có thể làm nhiều điều thú vị với sed, và vì thế có thể tốt hơn là thành thạo sử dụng nó với xargs.
Tôi đã tìm thấy bài này từ một bài đăng khác (không thể nhớ bài nào) và mặc dù không phải là trang nhã nhất, nó đơn giản và như một người dùng Linux mới làm cho tôi không gặp rắc rối
for i in *old_str* ; do mv -v "$i" "${i/\old_str/new_str}" ; done
nếu bạn có khoảng trắng hoặc các ký tự đặc biệt khác, hãy sử dụng \
for i in *old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done
đối với các chuỗi trong thư mục con sử dụng **
for i in *\*old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done
Có một cách dễ dàng hơn bằng cách sử dụng tệp tập lệnh đơn giản:
# sudo chmod +x /bin/replace_string_files_present_dir
mở tập tin trong gedit hoặc một trình soạn thảo bạn chọn, tôi sử dụng gedit ở đây.
# sudo gedit /bin/replace_string_files_present_dir
Sau đó, trong trình chỉnh sửa dán sau đây trong tập tin
#!/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.
Lưu tệp, đóng gedit , sau đó thoát khỏi thiết bị đầu cuối của bạn hoặc chỉ cần đóng nó và sau đó khởi động nó để có thể tải tập lệnh mới mà bạn đã thêm.
Điều hướng đến thư mục mà bạn có nhiều tệp bạn muốn chỉnh sửa. Sau đó chạy:
#replace_string_files_present_dir
Nhấn enter và điều này sẽ tự động thay thế chuỗi cũ và chuỗi cũ1 trong tất cả các tệp chứa chúng với chuỗi mới và chuỗi mới1 tương ứng.
Nó sẽ bỏ qua tất cả các thư mục và tệp không chứa các chuỗi cũ.
Điều này có thể giúp loại bỏ công việc gõ tẻ nhạt trong trường hợp bạn có nhiều thư mục với các tệp cần thay thế chuỗi. Tất cả bạn phải làm là điều hướng đến từng thư mục đó, sau đó chạy:
#replace_string_files_present_dir
Tất cả bạn phải làm là đảm bảo bạn đã bao gồm hoặc thêm tất cả các chuỗi thay thế như tôi đã trình bày ở trên:
replace "oldstring" "newstring" -- *
ở cuối tập tin / bin / thay_opes_files_present_dir .
Để thêm một chuỗi thay thế mới, chỉ cần mở tập lệnh mà chúng ta đã tạo bằng cách nhập đoạn mã sau vào terminal:
sudo gedit /bin/replace_string_files_present_dir
Đừng lo lắng về số lượng chuỗi thay thế bạn thêm vào, chúng sẽ không có hiệu lực nếu không tìm thấy chuỗi cũ .
.gitlab-ci.yml
hoặc a travis.yml
). Mỗi lượt bao gồm việc viết một tập lệnh để thực thi nó sau này là một kiểu chống mẫu, vì sau đó bạn sẽ cần phải tạo kịch bản cho việc tạo tập lệnh (và tôi thường lộn xộn, hầu hết thời gian)
$ thay thế "Từ" "Tới" - `find / path / to / library -type f`
(thay thế - một tiện ích thay thế chuỗi của Hệ thống cơ sở dữ liệu MySQL)