-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathreplace
More file actions
executable file
·115 lines (103 loc) · 3.56 KB
/
Copy pathreplace
File metadata and controls
executable file
·115 lines (103 loc) · 3.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/usr/bin/env bash
# author: andreasl
function show_help {
script_name="${0##*/}"
msg="${script_name}\n"
msg+="Interactively replace strings in files in a directory tree.\n"
msg+="Grep a given pattern on files with given file masks below the cwd and replace it with a"
msg+=" given string after asking for confirmation.\n"
msg+="\n"
msg+="Usage:\n"
msg+=" ${script_name} [-i|--ignore-case] <search-pattern> <replace-string> <file-pattern>...\n"
msg+="\n"
msg+="Examples:\n"
msg+=" ${script_name} 'echo' 'printf' *.sh # replace 'echo' with 'printf' in all *.sh files below the cwd\n"
msg+=" ${script_name} '2018' '2019' *.txt *.md # replace '2018' with '2019' in all *.txt and *.md files below the cwd\n"
msg+=" ${script_name} 'wind|rain' sun vacation.txt # replace all matching text passages with 'sun' in files called \"vacation.txt\"\n"
msg+=" ${script_name} -i 'foo' 'bar' *.txt # case-insensitive replace of 'foo' with 'bar' in all *.txt files\n"
msg+=" ${script_name} -h # print the usage message\n"
msg+=" ${script_name} --help # print the usage message\n"
printf "$msg"
}
ignore_case=false
while [[ "$#" -gt 0 ]]; do
case "$1" in
-h | --help)
show_help
exit 1
;;
-i | --ignore-case)
ignore_case=true
shift
;;
--)
shift
break
;;
*) break ;;
esac
done
if [ "$#" -lt 3 ]; then
printf 'Usage:\n'
printf -- " ${0##*/} -h|--help\n"
printf -- " ${0##*/} [-i|--ignore-case] <search-pattern> <replace-string> <file-pattern>...\n"
exit 1
fi
pattern_to_look_for="$1"
shift
string_to_replace_with="$1"
shift
grep_case_flag=()
sed_flags='g'
if [ "$ignore_case" = true ]; then
grep_case_flag=(-i)
sed_flags='gI'
fi
found_any_matches=false
for file_pattern in "$@"; do
# preview
if grep -HRn --color "${grep_case_flag[@]}" --include "$file_pattern" "$pattern_to_look_for" .; then
found_any_matches=true
fi
done
if [ "$found_any_matches" != true ]; then
printf 'Found no matches.\n'
exit 2
fi
read -r -e -n1 -p 'Do you want to continue? (y)es, (N)o, (i)nteractive: ' yes_no_i
if [[ "$yes_no_i" == [iI] ]]; then
interactive=true
elif [[ "$yes_no_i" != [yY] ]]; then
exit 0
fi
b='\e[1m'
n='\e[m'
files=()
for file_pattern in "$@"; do
files_lines="$(grep -Rl "${grep_case_flag[@]}" --include "$file_pattern" "$pattern_to_look_for" .)"
while IFS= read -r line; do
[ -z "$line" ] && continue
files+=("$line")
done <<<"$files_lines"
done
for file in "${files[@]}"; do
# do replace
if [ "$interactive" == true ]; then
printf "Change occurences in ${b}${file}${n}? (y)es, (n)o, (s)how: "
read -r -e -n1 yes_no_show
if [[ "$yes_no_show" == [sS] ]]; then
grep -Hn --color "${grep_case_flag[@]}" "$pattern_to_look_for" "$file"
printf "Change occurences in ${b}${file}${n}? [yY/nN]: "
read -r -e -n1 yes_no
if [[ "$yes_no" != [yY] ]]; then
continue
fi
elif [[ "$yes_no_show" != [yY] ]]; then
continue
fi
fi
sed --follow-symlinks -i "s@${pattern_to_look_for}@${string_to_replace_with}@${sed_flags}" "$file" # GNU
# Mac BSD sed (note: BSD sed does not support the I flag for case-insensitive substitution)
# sed -i '' "s@${pattern_to_look_for}@${string_to_replace_with}@${sed_flags}" "$file"
grep -FHn --color "$string_to_replace_with" "$file"
done