다음 형식으로 디렉토리를 평평하게하려면 어떻게해야합니까?
전에: ./aaa/bbb/ccc.png
후: ./aaa-bbb-ccc.png
./foo/bar/baz.png
하고 ./foo-bar-baz.png
모두 존재합니다. 나는 당신이 후자를 전자로 바꾸고 싶지 않다고 가정합니까?
다음 형식으로 디렉토리를 평평하게하려면 어떻게해야합니까?
전에: ./aaa/bbb/ccc.png
후: ./aaa-bbb-ccc.png
./foo/bar/baz.png
하고 ./foo-bar-baz.png
모두 존재합니다. 나는 당신이 후자를 전자로 바꾸고 싶지 않다고 가정합니까?
답변:
경고 : 대부분의 명령을 브라우저에 직접 입력했습니다. 주의 사항 강사.
zsh 및 zmv 사용 :
zmv -o -i -Qn '(**/)(*)(D)' '${1//\//-}$2'
설명 : 패턴 **/*
은 현재 디렉토리의 서브 디렉토리에있는 모든 파일을 재귀 적으로 일치시킵니다 (현재 디렉토리의 파일과 일치하지는 않지만 이름을 바꿀 필요는 없습니다). 괄호의 처음 두 쌍에 대해 참조로 할 수있는 기 $1
및 $2
대체 텍스트. 마지막 괄호 쌍은 D
glob 한정자를 추가하여 도트 파일이 생략되지 않도록합니다. 기존 파일을 덮어 쓸 것인지 묻는 메시지가 표시되도록 옵션 -o -i
을 전달하는 것을 의미합니다 .-i
mv
POSIX 도구 만 사용 :
find . -depth -exec sh -c '
for source; do
case $source in ./*/*)
target="$(printf %sz "${source#./}" | tr / -)";
mv -i -- "$source" "${target%z}";;
esac
done
' _ {} +
설명 : case
명령문이 현재 디렉토리 및 현재 디렉토리의 최상위 서브 디렉토리를 생략합니다. target
소스 파일 이름 ( $0
)을 포함하고 선행 줄을 ./
제거하고 모든 슬래시를 대시로 바꾸고 final을 포함 z
합니다. 마지막 z
은 파일 이름이 줄 바꿈으로 끝나는 경우입니다. 그렇지 않으면 명령 대체가 파일을 제거합니다.
find
지원하지 않는 경우 -exec … +
(OpenBSD,보고 있습니다) :
find . -depth -exec sh -c '
case $0 in ./*/*)
target="$(printf %sz "${0#./}" | tr / -)";
mv -i -- "$0" "${target%z}";;
esac
' {} \;
bash (또는 ksh93)를 사용하면 슬래시를 대시로 대체하기 위해 외부 명령을 호출 할 필요가 없으며 ksh93 매개 변수 확장을 문자열 대체 구문과 함께 사용할 수 있습니다 ${VAR//STRING/REPLACEMENT}
.
find . -depth -exec bash -c '
for source; do
case $source in ./*/*)
source=${source#./}
target="${source//\//-}";
mv -i -- "$source" "$target";;
esac
done
' _ {} +
for source
예는 내가 마지막으로 당신은 (일반적으로) 사용한 이유를 발견했습니다 ... 처음 소개 파일 / 디렉토리를 그리워 _
로 $0
:) ... 그리고 덕분에 좋은 답변을. 나는 그들로부터 많은 것을 배웁니다.
여기에 좋은 대답이 있지만 다음과 같이 더 직관적입니다 bash
.
find aaa -type f -exec sh -c 'new=$(echo "{}" | tr "/" "-" | tr " " "_"); mv "{}" "$new"' \;
aaa
기존 디렉토리는 어디에 있습니까 ? 포함 된 파일은 현재 디렉토리로 이동합니다 (aaa에는 빈 디렉토리 만 남음). 두 호출tr
디렉토리와 공백을 모두 처리 위한 두 (이스케이프 된 슬래시에 대한 논리없이 독자를위한 연습).
나는 이것을보다 직관적이고 조정하기 쉽다고 생각합니다. 즉, find
.png 파일 만 찾으려고 하면 매개 변수를 변경할 수 있습니다 . tr
통화 를 변경 하거나 필요에 따라 추가 할 수 있습니다 . 그리고 그것이 옳은 일을 할 것인지 육안으로 확인 echo
하기 전에 추가 할 수 있습니다 mv
(그러면 echo
상황이 올바르게 보일 때만 추가없이 반복하십시오 :
find aaa -name \*.png -exec sh -c 'new=$(echo "{}" | tr "/" "-" | tr " " "_"); echo mv "{}" "$new"' \;
또한 후자는 두 개가 최종 파일 이름에 재미있는 유물을 남길 수 있기 find aaa
때문에 find .
... 또는 find aaa/
...을 사용 하지 않습니다 .
find . -mindepth 2 -type f -name '*' |
perl -l000ne 'print $_; s/\//-/g; s/^\.-/.\// and print' |
xargs -0n2 mv
참고 :이 포함 된 파일 이름에는 작동하지 않습니다 \n
.
이것은 물론 형식 f
파일 만 이동 합니다.
유일한 이름 충돌은 기존 파일에 존재합니다. pwd에
이 기본 하위 집합으로 테스트
rm -fr junk
rm -f junk*hello*
mkdir -p junk/junkier/junkiest
touch 'hello hello'
touch 'junk/hello hello'
touch 'junk/junkier/hello hello'
touch 'junk/junkier/junkiest/hello hello'
를 야기하는
./hello hello
./junk-hello hello
./junk-junkier-hello hello
./junk-junkier-junkiest-hello hello
여기에 ls
버전이 있습니다. 의견 환영합니다. 이 같은 엉뚱한 파일 이름에는 작동
"j1ळ\n\001\n/j2/j3/j4/\nh h\n"
하지만 실제로 함정에 대해 알고 싶습니다. "악성 인들이 ls
실제로 (견고하게) 그것을 할 수 있는가?"
ls -AbQR1p * | # paths in "quoted" \escaped format
sed -n '/":$/,${/.[^/]$/p}' | # skip files in pwd, blank and dir/ lines
{ bwd="$PWD"; while read -n1; # save base dir strip leading "quote
read -r p; do # read path
printf -vs "${p%\"*}" # strip trailing quote"(:)
[[ $p == *: ]] && { # this is a directory
cd "$bwd/$s" # change into new directory
rnp="${s//\//-}"- # relative name prefix
} || mv "$s" "$bwd/$rnp$s"
done; }
파일 이름 + 경로를 tr
명령으로 파이프하십시오 .tr <replace> <with>
for FILE in `find aaa -name "*.png"`
do
NEWFILE=`echo $FILE | tr '/' '-'`
cp -v $FILE $NEWFILE
done
cp
을 cp -v "$FILE" "$NEWFILE"
주기 위해 줄을 바꾸겠습니까 ? (또한 PNG 파일 만 가정해서는 안됩니다.)
cp
줄에 따옴표를 추가하는 것만으로 는 충분하지 않습니다. 루프를 find
사용하여 출력 을 구문 분석하는 전체 접근 방식에 for
결함이 있습니다. 사용의 유일한 안전한 방법이 find
함께있는 -exec
, 또는 -print0
(이하 휴대용 가능한 경우 -exec
). 더 강력한 대안을 제안하지만 현재 귀하의 질문이 잘못 지정되었습니다.
파일 이름의 공백에 안전 :
#!/bin/bash
/bin/find $PWD -type f | while read FILE
do
_new="${FILE//\//-}"
_new="${_new:1}"
#echo $FILE
#echo $_new
/bin/mv "$FILE" "$_new"
done
명백한 이유 cp
대신에 채굴을 mv
했지만 같은 결과를 낳아야합니다.
type find
find is /usr/bin/find
내 컴퓨터에서 -> . 사용 PATH
하는 스크립트의 변수 이름으로하는 것은 끔찍한 생각이다. 또한 스크립트는 파일 이름을 공백이나 백 슬래시로 엉망으로 만듭니다. read
명령 을 잘못 사용하기 때문입니다 (이 사이트에서 검색 IFS read -r
).
find is hashed (/bin/find)
관련 방법? 다른 배포판이 다른가요?
PATH
는 모든 유닉스 시스템이 사용 하는 환경 변수 의 요점이 빠져 있다고 제안하는 것 같습니다 . 작성하면 /bin/find
스크립트가없는 모든 시스템 (Gilles, mine 및 아마도 OP)에서 실제로 스크립트가 손상됩니다 /bin/find
(예 : b / c가 있습니다 /usr/bin/find
). PATH
환경 변수의 요점은 이것을 비 문제로 만드는 것입니다.
$(pwd)
이미 변수에서 사용할 수 있습니다 : $PWD
. 그러나 여기서 절대 경로를 사용 해서는 안됩니다 . 예를 들어 스크립트를 호출 /home/tim
하면로 이름 /home/tim/some/path
을 바꾸려고 시도 합니다 /home-tim-some-path
.