명령이 파일 이름만 인쇄 하도록 하는 방법이 있습니까 rename
(접두사 XXX renamed as
나 괄호는 제외)? 유일한 옵션이 아니라면 정규식을 사용하지 않는 것이 좋습니다.
묻는 이유: 파일 이름이 보기 흉해 보이지 않도록 여러 번 연속해서 파일 이름(실제로는 파일 목록)을 바꾸고 싶습니다. 첫 번째 이름 바꾸기에서 이름이 변경된 경우 두 번째 이름 바꾸기 명령에 입력할 수 있는 파일의 새 이름을 얻는 쉬운 방법이 없기 때문에 이는 어렵습니다.
예
%20
그러면 웹에서 다운로드한 파일의 이름이 로 바뀌게 됩니다 . 동일한 파이프라인의 후속 명령에서는 이름을 로 바꾸고 싶을 수도 있습니다 . 정규 표현식이 복잡하기 때문에(가능한 경우) 단일 이름 바꾸기 명령을 사용하고 싶지 않습니다.
%28
(
find -iname "*%20*" | xargs -n 1 rename --some-option 's/%20/ /g' | xargs -n 1 rename --some-option 's/%28/(/g'
답변1
일련의 sed
명령을 사용하여 시작 파일 이름을 최종 파일 이름으로 변환한 다음 수행하십시오.하나 mv
실제 이름 바꾸기 파일:
for i in *%*
do
printf "mv -v '%s' '%s'\n" "$i" \
"$( sed -e 's/%20/ /g' \
-e 's/%28/(/g' \
<<< "$i" )"
done
이 명령 목록은 실제로 파일을 변경하지 않으며 이는 좋은 것입니다. mv
실제로 원하는 작업을 수행하는 데 사용할 수 있는 명령을 출력할 뿐입니다 .
%20
다음 을 포함하는 몇 가지 샘플 파일을 만들어 보겠습니다 %28
.
$ for i in foo bar farkle
> do
> touch $i"%20".txt; touch $i"%28".txt; touch $i"%20-%28".txt
> done
$ ls -1
bar%20-%28.txt
bar%20.txt
bar%28.txt
farkle%20-%28.txt
farkle%20.txt
farkle%28.txt
foo%20-%28.txt
foo%20.txt
foo%28.txt
이제 시작 부분에 제공된 명령 목록을 실행해 보겠습니다.
$ for i in *%*
> do
> printf "mv -v '%s' '%s'\n" "$i" \
> "$(sed -e 's/%20/ /g' -e 's/%28/(/g' <<< "$i")"
> done
mv -v 'bar%20-%28.txt' 'bar -(.txt'
mv -v 'bar%20.txt' 'bar .txt'
mv -v 'bar%28.txt' 'bar(.txt'
mv -v 'farkle%20-%28.txt' 'farkle -(.txt'
mv -v 'farkle%20.txt' 'farkle .txt'
mv -v 'farkle%28.txt' 'farkle(.txt'
mv -v 'foo%20-%28.txt' 'foo -(.txt'
mv -v 'foo%20.txt' 'foo .txt'
mv -v 'foo%28.txt' 'foo(.txt'
명령 순서가 mv
올바른 것으로 보이면 위쪽 화살표를 사용하여 명령을 다시 실행하십시오. 단, 이번에는 명령을 표시하는 대신 | sh
실제로 명령을 실행하도록 끝에 추가하십시오 .mv
답변2
본질적으로 이것은 해결된 문제인 URL 디코딩 연습인 것으로 보입니다.
다음 이름으로 저장하세요 rename_script.sh
.
DECODED="$(awk -niord '{printf RT?$0chr("0x"substr(RT,2)):$0}' RS=%.. <<< "${1}")"
[ ! -f "${1}" ] && echo "Source not found" && exit 1
[ -f "${DECODED}" ] && echo "Target already exists" && exit 1
[ "${1}" != "${DECODED}" ] && mv -i "${1}" "${DECODED}" || echo "Nothing to do"
다음과 같이 호출하세요.
find -name "*%*" -print0 | xargs -n1 -0 ./rename_script.sh
이 답변을 적극 추천합니다. https://stackoverflow.com/a/14000368/2858703
답변3
find . -type f -name '*%*' -execdir bash -c '
name=$1
name=${name//%20/ } # replace each %20 by a space
name=${name//%28/(} # replace each %28 by a (
mv "$1" "$name"' bash {} \;
find
이는 이름에 문자가 포함된 현재 디렉토리 안이나 아래의 일반 파일을 찾는 데 사용됩니다 %
. 이러한 각 파일에 대해 bash
주어진 파일 이름에 대해 언급한 두 가지 대체를 수행한 다음 파일 이름을 바꾸는 짧은 스크립트가 실행됩니다.
추가 매개변수 대체를 쉽게 추가하여 파일 이름의 다른 문자열을 제거하거나 변경할 수 있습니다.
잠재적으로 더 빠른 방법은 동일한 작업을 수행하는 간단한 루프를 작성하는 것입니다( bash
이 특정 변형에 셸이 사용된다고 가정).
shopt -s nullglob dotglob globstar
for pathname in ./**/*%*; do
# skip pathnames to non-regular (or links to non-regular) files
[[ ! -f "$pathname" ]] && continue
name=${pathname##*/} # strip off directory components
name=${name//%20/ } # ... so that we don't accidentally
name=${name//%28/(} # ... modify the directory path
# the destination is made up by the directory path
# (original pathname with filename stripped off)
# followed by the new name
mv "$pathname" "${pathname%/*}/$name"
done
쉘 nullglob
옵션을 사용하면 패턴이 ./**/*%*
다음으로 확장됩니다.아무것도 없다일치하는 항목이 없는 경우(일반적으로 확장 없음) dotglob
와일드카드 패턴이 숨겨진 이름을 처리하도록 허용하고 하위 디렉터리에 대한 "재귀적" 일치를 globstar
허용합니다 **
.
find
와일드카드 패턴의 내용 대신 경로 이름을 생성하는 데 사용할 두 번째 루프를 조정합니다 (예: bash
4 이전 버전에서 실행 중이 아닌 경우 **
).
find . -type f -name '*%*' -exec bash -c '
for pathname do
name=${pathname##*/} # strip off directory components
name=${name//%20/ } # ... so that we don't accidentally
name=${name//%28/(} # ... modify the directory path
# the destination is made up by the directory path
# (original pathname with filename stripped off)
# followed by the new name
mv "$pathname" "${pathname%/*}/$name"
done' bash {} +