我正在尝试重命名我的应用程序中的许多文件,并且需要能够在应用程序根目录下通过git(即git mv%filenamematch %% replacement%)在所有子目录中进行重命名,只替换匹配的文本。我对bash脚本没有好处。
更新:如果还重命名匹配的目录也会很好!
答案 0 :(得分:28)
这应该可以解决问题:
for file in $(git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq); git mv $file $(echo $file | sed -e 's/%filenamematch%/%replacement%/')
要了解这是做什么的,你需要用“|”来理解管道并用“$(...)”替换命令。这些强大的shell结构允许我们组合几个命令来获得我们需要的结果。请参阅Pipelines和Command Substitution。
以下是这个单行中发生的事情:
git ls-files
:这会在Git存储库中生成一个文件列表。它类似于你从ls
获得的内容,除了它只输出Git项目文件。从此列表开始确保.git /目录中没有任何内容被触及。
| grep %filenamematch%
:我们从git ls-files
获取列表并通过grep将其过滤以将其过滤为仅包含我们正在查找的单词或模式的文件名。
| sed -e 's/\(%filenamematch%[^/]*\).*/\1/'
:我们通过sed(流编辑器)管理这些匹配,执行(-e)sed的s(替换)命令以在匹配后切掉任何/后续字符目录(如果碰巧是一个)。
| uniq
:如果匹配是一个目录,现在我们已经删除了包含的目录和文件,可能会有很多匹配的行。我们使用uniq将它们全部组合成一行。
for file in ...
:shell的"for" command将遍历列表中的所有项目(文件名)。依次为每个文件名,它分配给变量“$ file”,然后在分号(;)之后执行命令。
sed -e 's/%filenamematch%/%replacement%/'
:我们使用echo通过sed管道每个文件名,再次使用它的替换命令 - 这次在文件名上执行模式替换。
git mv
:我们使用此git命令将现有文件($ file)转换为新文件名(由sed更改的文件名)。
更好地理解这一点的一种方法是单独观察这些步骤。为此,请在shell中运行以下命令,并观察输出。所有这些都是非破坏性的,只为您的观察产生列表:
git ls-files
git ls-files | grep %filenamematch%
git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/'
git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq
for file in $(git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq); echo $file
for file in $(git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq); echo $file | sed -e 's/%filenamematch%/%replacement%/'
答案 1 :(得分:14)
使用命令rename
:
rename 's/old/new/' *
然后通过添加新文件并删除旧文件来使用Git注册更改:
git add .
git ls-files -z --deleted | xargs -0 git rm
在较新版本的Git中,您可以改为使用--all
标志:
git add --all .
答案 2 :(得分:12)
晚会但是,这应该在BASH中工作(对于文件和目录,但我对目录要小心):
find . -name '*foo*' -exec bash -c 'file={}; git mv $file ${file/foo/bar}' \;
答案 3 :(得分:5)
git mv
?
(假设你在一个有合理shell的平台上!)
建立在@ jonathan-camenish上:#(有人可以将其编辑成真正的链接吗?)
# things between backticks are 'subshell' commands. I like the $() spelling over ``
# git ls-files -> lists the files tracked by git, one per line
# | grep somestring -> pipes (i.e., "|") that list through a filter
# '|' connects the output of one command to the input of the next
# leading to: for file in some_filtered_list
# git mv f1 f2 -> renames the file, and informs git of the move.
# here 'f2' is constructed as the result of a subshell command
# based on the sed command you listed earlier.
for file in `git ls-files | grep filenamematch`; do git mv $file `echo $file | sed -e 's/%filenamematch%/%replacement%/'`; done
这是一个较长的例子(以bash或类似方式)
mkdir blah; cd blah;
touch old_{f1,f2,f3,f4} same_{f1,f2,f3}
git init && git add old_* same_* && git commit -m "first commit"
for file in $(git ls-files | grep old); do git mv $file $(echo $file | sed -e 's/old/new/'); done
git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# renamed: old_f1 -> new_f1
# renamed: old_f2 -> new_f2
# renamed: old_f3 -> new_f3
# renamed: old_f4 -> new_f4
#
请参阅:http://en.wikibooks.org/wiki/Ad_Hoc_Data_Analysis_From_The_Unix_Command_Line/
答案 4 :(得分:3)
这适用于我的用例:
ls folder*/*.css | while read line; do git mv -- $line ${line%.css}.scss; done;
说明:
ls folder*/*.css
- 使用ls
获取包含与glob模式匹配的CSS文件的所有目录的列表。 (以folder
开头并包含.css
个扩展名的文件的目录while read line
- 逐行读取ls
命令的结果输出do git mv -- $line ${line%.css}.css
- 逐行输出git mv
执行$line
,同时匹配每个文件名的开头并排除.css
扩展名(使用${line%
并添加新的.scss
扩展名(--
用于防止文件名和标记之间存在歧义)以下代码可用于&#34;干运行&#34; (实际上不会执行git mv
):
ls variant*/*.css | while read line; do echo git mv $line to ${line%.css}.scss; done;
答案 5 :(得分:1)
我通过使用来解决这个问题
https://github.com/75lb/renamer - 完美地工作:-)
没有明确地做git mv
但是git似乎完全处理了结果。
当我按照最高回答中的所有步骤操作时,我在最后一步遇到困难,当我的控制台响应时
for pipe quote>
如果有人能解释这一点,我会很感激!
答案 6 :(得分:0)
我通常使用NetBeans来执行此类操作,因为当有更简单的方法时我会避开命令行。 NetBeans对git有一些支持,您可以通过“收藏夹”选项卡在任意目录/文件中使用它。
答案 7 :(得分:0)
这是我如何将 .less
文件夹中的所有 ./src
文件重命名为 .scss
find ./src -type f |grep "\.less$" | while read line; do git mv -- $line ${line%.less}.scss; done;