Created
July 7, 2016 03:37
-
-
Save kouichi-c-nakamura/4a8674bfa3e2b5de96930c7ad2017ce8 to your computer and use it in GitHub Desktop.
Macに保存していたデータをWindowsマシンへ移行する時の苦労話 ref: http://qiita.com/kouichi-c-nakamura/items/518cd401e35889646b2e
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
csrutil disable | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
csrutil enable | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ditto -v sourcefolder destinationfolder |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* ===> x | |
: ===> - | |
? ===> _ | |
" ===> ' | |
< ===> [ | |
> ===> ] | |
| ===> _ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function [report,failures] = correctWinIncompatibleFileNames(parentFolder,varargin) | |
% [report,failures] = correctWinIncompatibleFileNames(parentFolder) | |
% [report,failures] = correctWinIncompatibleFileNames(parentFolder,dorename) | |
% | |
% correctWinIncompatibleFileNames runs recursively across folder hierarchy | |
% to correct invalid file names in Windows OS. You can use this only on Mac | |
% platform though. | |
% | |
% * ===> x | |
% : ===> - | |
% ? ===> _ | |
% " ===> ' | |
% < ===> [ | |
% > ===> ] | |
% | ===> _ | |
% | |
% INPUT ARGUMENTS | |
% parentFolder A valid foder path | |
% | |
% dorename true (default) | false | |
% If you choose false, correctWinIncompatibleFileNames does | |
% not run Terminal's mv command, but only returns report | |
% table for you to simulate the outcome. | |
% | |
% OUTPUT ARGUMENT | |
% report A table output | |
% Variables | |
% Folder | |
% OriginalNames | |
% NewNames | |
% Illegals | |
% Bytes | |
% Date | |
% | |
% failures Similar to report but for failures | |
% | |
% | |
%% Filter for WinMerge | |
% | |
% ## This is a directory/file filter template for WinMerge | |
% name: Ignore Asterisk and Colon | |
% desc: Ignore files whose names include asterisk (*) and Colon (:) | |
% | |
% ## Select if filter is inclusive or exclusive | |
% ## Inclusive (loose) filter lets through all items not matching rules | |
% ## Exclusive filter lets through only items that match to rule | |
% ## include or exclude | |
% def: include | |
% | |
% ## Filters for filenames begin with f: | |
% ## Filters for directories begin with d: | |
% ## (Inline comments begin with " ##" and extend to the end of the line) | |
% | |
% f: \w+\*\w*\.{0,1}\w* ## Filter for filename | |
% f: \: | |
% f: \? | |
% | |
% ##d: \\subdir$ ## Filter for directory | |
% | |
% | |
% | |
% See also | |
% unix, movefile, dir, preallocatestruct, regexptranslate, | |
% correctWinIncompatibleFileNames_test, | |
% correctWinIncompatibleFileNames_fixture | |
% | |
% https://msdn.microsoft.com/en-us/library/aa365247 | |
p = inputParser; | |
p.addRequired('parentFolder',@(x) isdir(x)); | |
p.addOptional('dorename',true,@(x) isscalar(x) && x == 0 || x == 1); | |
p.parse(parentFolder,varargin{:}); | |
dorename = p.Results.dorename; | |
assert(isdir(parentFolder),... | |
'correctFileNamesOnWindows:parentFolder:invalid',... | |
'folder %s is invalid for a folder',parentFolder); | |
cs = repmat({''},1e5,1); % up to 100000 illegal files at one time | |
cc = cell(1e5,1); | |
nan = NaN(1e5,1); | |
report = table(cs,cs,cs,cc,nan,cs); | |
report.Properties.VariableNames = {'Folder','OriginalNames','NewNames','Illegals','Bytes','Date'}; | |
failures = table(cs,cs,cs,cc,nan,cs,cs); | |
failures.Properties.VariableNames = [report.Properties.VariableNames,{'Cmdout'}]; | |
clear cs c | |
row = 0; | |
row2 = 0; % for failures | |
[report,row,failures,row2] = doOneFolder(parentFolder,report,row,dorename,failures,row2); | |
report(row+1:end,:) = []; | |
failures(row2+1:end,:) = []; | |
if ~dorename | |
warning('correctWinIncompatibleFileNames:dorename:false',... | |
'No file name has been changed by correctWinIncompatibleFileNames.') | |
end | |
end | |
%-------------------------------------------------------------------------- | |
function [report,row,failures,row2] = doOneFolder(thisFolder,report,row,dorename,failures,row2) | |
% report is a table | |
list = dir(thisFolder); | |
names = {list(:).name}'; | |
% if there is a folder | |
n = length(names); | |
for i = 1:n | |
if strcmp(list(i).name,'.') | |
continue | |
elseif strcmp(list(i).name,'..') | |
continue | |
end | |
if list(i).isdir | |
[report,row,failures,row2] = doOneFolder(fullfile(thisFolder,list(i).name),... | |
report,row,dorename,failures,row2); | |
else | |
origName = list(i).name; | |
NewNames = origName; | |
illegal_count = 0; | |
illegals = preallocatestruct({'char','newchar','startIndex'},[64,1]); | |
% correct illegal file names | |
% https://msdn.microsoft.com/en-us/library/aa365247 | |
[illegals,illegal_count,NewNames] = findillegals('*','x',... | |
NewNames,illegals,illegal_count); | |
[illegals,illegal_count,NewNames] = findillegals(':','-',... | |
NewNames,illegals,illegal_count); | |
[illegals,illegal_count,NewNames] = findillegals('?','_',... | |
NewNames,illegals,illegal_count); | |
[illegals,illegal_count,NewNames] = findillegals('"','\''',... | |
NewNames,illegals,illegal_count); | |
[illegals,illegal_count,NewNames] = findillegals('<','[',... | |
NewNames,illegals,illegal_count); | |
[illegals,illegal_count,NewNames] = findillegals('>',']',... | |
NewNames,illegals,illegal_count); | |
[illegals,illegal_count,NewNames] = findillegals('|','_',... | |
NewNames,illegals,illegal_count); | |
%% KEEP THESE EXAMPLES | |
% | |
% movefile('abc"de.rtf','abc''de.rtf'); % works on Mac | |
% | |
% unix('mv abc\"de\.rtf abcde.rtf'); % works on Mac | |
% | |
% unix('mv abc\"de.rtf abcde.rtf'); % works on Mac | |
% | |
% unix('mv abc"de.rtf abcde.rtf'); % does not work on Mac | |
% % /bin/bash: -c: line 0: unexpected EOF while looking for matching `"' | |
% % /bin/bash: -c: line 1: syntax error: unexpected end of file | |
% | |
% unix('mv "abc\"de.rtf" abcde.rtf'); % works on Mac | |
% | |
% | |
% | |
% unix('mv abc\"de.rtf "abc''de.rtf"'); % works on Mac | |
% | |
% unix('mv abc\"de.rtf abc\''de.rtf'); % works on Mac | |
% | |
% | |
% | |
% movefile('abc\*de.rtf','abcxde.rtf'); % does not work on Mac | |
% | |
% unix('mv abc\*de\.rtf abcxde\.rtf'); % works on Mac | |
% | |
illegals(illegal_count+1:end) = []; % up to 64 illegals | |
if illegal_count > 0 | |
% sort illegals | |
startInd = [illegals(:).startIndex]; | |
[~,ind] = sort(startInd); | |
illegals = illegals(ind); | |
if ismac | |
if dorename | |
% escape2 = @(x) regexprep(x,'"','\\"'); % need to escape " | |
% escape = @(x) regexprep(regexptranslate('escape',fullfile(thisFolder,x)),'\s','\\ '); | |
% %NOTE need to escape a space with \ even after regexptranslate | |
% | |
% src = escape2(escape(origName)); | |
% dst = escape2(escape(NewNames)); | |
src = fullfile(thisFolder,origName); | |
dst = fullfile(thisFolder,NewNames); | |
src = findQinpath(src); | |
dst = findQinpath(dst); | |
cmd = sprintf('mv -f %s %s',src,dst); | |
[status,cmdout] = unix(cmd,'-echo'); | |
%NOTE movefile won't work properly with \* | |
% movefile(src,dst,'f'); % rename the file | |
% movefile(fullfile(thisFolder,origName),fullfile(thisFolder,NewNames),'f') | |
if status == 0 % success | |
row = row + 1; | |
% fprintf('Renamed %s to %s \t\tin %s\n',origName,NewNames,thisFolder); | |
else | |
row2 = row2 + 1; | |
disp(cmdout) | |
warning('Failed to rename %s to %s in %s\n',origName,NewNames,thisFolder); | |
thisfailure = table({thisFolder},{origName},{NewNames},{illegals},... | |
list(i).bytes,{datestr(list(i).datenum)},{cmdout}); | |
thisfailure.Properties.VariableNames = failures.Properties.VariableNames; | |
failures(row2,:) = thisfailure; | |
continue | |
end | |
else | |
row = row + 1; | |
end | |
else | |
if dorename | |
error('correctFileNamesOnWindows:OS:notmac',... | |
'This function is for Mac OS X only if dorename option is true'); | |
else | |
row = row + 1; | |
end | |
end | |
thisrep = table({thisFolder},{origName},{NewNames},{illegals},... | |
list(i).bytes,{datestr(list(i).datenum)}); | |
thisrep.Properties.VariableNames = report.Properties.VariableNames; | |
report(row,:) = thisrep; | |
end | |
end | |
end | |
end | |
%-------------------------------------------------------------------------- | |
function [illegals,illegal_count,NewNames] = findillegals(target,replacement,... | |
NewNames,illegals,illegal_count) | |
targetreg = regexptranslate('escape',target); | |
if isregexpmatched(NewNames,targetreg) | |
startIndex = regexp(NewNames,targetreg); | |
NewNames = regexprep(NewNames,targetreg,replacement); | |
for k = 1:length(startIndex) | |
illegals(illegal_count + k).char = target; | |
illegals(illegal_count + k).newchar = replacement; | |
illegals(illegal_count + k).startIndex = startIndex(k); | |
end | |
illegal_count = illegal_count + length(startIndex); | |
end | |
end | |
%-------------------------------------------------------------------------- | |
function pathout = findQinpath(path) | |
% | |
% pathout = findQinpath(path) | |
% | |
% findQinpath searches for ' or " | |
% | |
% If only 's or "s are found, then encompass path with the other quotation | |
% mark. | |
% | |
% If both ' and " are found, make sure they are escaped by \? | |
% | |
% | |
%NOTE | |
% unix() takes bash command. By default, you don't need to use | |
% quatations for file names, but that makes you escape all the | |
% space and other special characters in file path. And the code | |
% gets difficult to read. | |
% | |
% You can use double " or single ' quotation marks for string. So | |
% | |
% unixt('mv "filepath1" "filepath2") | |
% | |
% may be generally a good choice, because you don't need to escpae special | |
% characters within quatation marks and " does not interfere with MATLAB's | |
% use of '. | |
% | |
% When a quotation mark is used in a file path, then you need to be | |
% careful. If only single quotation mark (') is used, then you can use | |
% doble quotation marks for the entire file path string, and vice versa. | |
% | |
% In case the file path uses both single and double quotation | |
% marks, then you can only escape with \. | |
singlefound = isregexpmatched(path,''''); | |
doublefound = isregexpmatched(path,'"'); | |
if singlefound && ~doublefound | |
pathout = ['"',path,'"']; | |
elseif ~singlefound && doublefound | |
pathout = ['''',path,'''']; | |
elseif ~singlefound && ~doublefound | |
pathout = ['"',path,'"']; | |
elseif singlefound && doublefound | |
path1 = regexptranslate('escape',path); | |
path2 = regexprep(path1,'\s','\\ '); | |
path3 = regexprep(path2,'"','\\"'); % need to escape " | |
pathout = regexprep(path3,'''','\\'''); % need to escape ' | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment