Unix 이름 바꾸기 명령 파이프

Unix 이름 바꾸기 명령 파이프

명령이 파일 이름만 인쇄 하도록 하는 방법이 있습니까 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와일드카드 패턴의 내용 대신 경로 이름을 생성하는 데 사용할 두 번째 루프를 조정합니다 (예: bash4 이전 버전에서 실행 중이 아닌 경우 **).

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 {} +

관련 정보