programing

bash 스크립트를 사용하여 파일 이름의 공백을 바꾸는 방법

lovejava 2023. 4. 29. 08:08

bash 스크립트를 사용하여 파일 이름의 공백을 바꾸는 방법

지정된 루트 디렉터리에서 시작하는 파일 및 디렉터리 이름의 공백을 반복적으로 밑줄로 대체할 수 있는 안전한 솔루션을 추천할 수 있는 사람이 있습니까?예:

$ tree
.
|-- a dir
|   `-- file with spaces.txt
`-- b dir
    |-- another file with spaces.txt
    `-- yet another file with spaces.pdf

다음이 됩니다.

$ tree
.
|-- a_dir
|   `-- file_with_spaces.txt
`-- b_dir
    |-- another_file_with_spaces.txt
    `-- yet_another_file_with_spaces.pdf

사용자:

for f in *\ *; do mv "$f" "${f// /_}"; done

비록 재귀적이지는 않지만, 꽤 빠르고 간단합니다.여기 있는 누군가가 그것을 재귀적으로 업데이트할 수 있다고 확신합니다.

${f// /_}part는 bash의 매개 변수 확장 메커니즘을 사용하여 매개 변수 내의 패턴을 제공된 문자열로 바꿉니다.관련 구문은 다음과 같습니다.${parameter/pattern/string}https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html 또는 http://wiki.bash-hackers.org/syntax/pe 을 참조하십시오.

사용하다rename(일명)prename시스템에 이미 있을 수 있는 Perl 스크립트입니다.두 단계로 수행합니다.

find . -name "* *" -type d | rename 's/ /_/g'    # do the directories first
find . -name "* *" -type f | rename 's/ /_/g'

위르겐의 답변에 기초하고 "Revision 1.5 1998/12/18 16:31 rmb1" 버전을 사용하여 단일 바인딩에서 여러 계층의 파일 및 디렉토리를 처리할 수 있습니다./usr/bin/rename(Perl 스크립트):

find . -depth -name "* *" -execdir rename 's/ /_/g' "{}" \;
find . -depth -name '* *' \
| while IFS= read -r f ; do mv -i "$f" "$(dirname "$f")/$(basename "$f"|tr ' ' _)" ; done

처음에는 제가 디렉토리를 생각하지 못했기 때문에 제대로 이해하지 못했습니다.

사용할 수 있습니다.detox더그 하플 지음

detox -r <folder>

찾기/이름 바꾸기 솔루션.rename은 util-linux의 일부입니다.

공백 파일 이름이 공백 디렉토리의 일부가 될 수 있으므로 먼저 깊이를 줄여야 합니다.

find /tmp/ -depth -name "* *" -execdir rename " " "_" "{}" ";"

다음을 사용할 수 있습니다.

find . -depth -name '* *' | while read fname 

do
        new_fname=`echo $fname | tr " " "_"`

        if [ -e $new_fname ]
        then
                echo "File $new_fname already exists. Not replacing $fname"
        else
                echo "Creating new file $new_fname to replace $fname"
                mv "$fname" $new_fname
        fi
done

bash 4.0

#!/bin/bash
shopt -s globstar
for file in **/*\ *
do 
    mv "$file" "${file// /_}"       
done

나이딤의 대답의 재귀 버전입니다.

find . -name "* *" | awk '{ print length, $0 }' | sort -nr -s | cut -d" " -f2- | while read f; do base=$(basename "$f"); newbase="${base// /_}"; mv "$(dirname "$f")/$(basename "$f")" "$(dirname "$f")/$newbase"; done

macOS에서

선택한 답처럼.

brew install rename

# 
cd <your dir>
find . -name "* *" -type d | rename 's/ /_/g'    # do the directories first
find . -name "* *" -type f | rename 's/ /_/g'

MacOS를 사용하여 이 문제를 해결하는 데 어려움을 겪고 있는 사람들을 위해 먼저 모든 도구를 설치합니다.

 brew install tree findutils rename

그런 다음 이름을 변경해야 할 때 GNU find(gfind)의 별칭을 find로 만듭니다.그런 다음 @Michel Krelin 코드를 실행합니다.

alias find=gfind 
find . -depth -name '* *' \
| while IFS= read -r f ; do mv -i "$f" "$(dirname "$f")/$(basename "$f"|tr ' ' _)" ; done   

다음은 stderr에 "file already exists" 경고를 기록하는 (상당히 상세한) find-exec 솔루션입니다.

function trspace() {
   declare dir name bname dname newname replace_char
   [ $# -lt 1 -o $# -gt 2 ] && { echo "usage: trspace dir char"; return 1; }
   dir="${1}"
   replace_char="${2:-_}"
   find "${dir}" -xdev -depth -name $'*[ \t\r\n\v\f]*' -exec bash -c '
      for ((i=1; i<=$#; i++)); do
         name="${@:i:1}"
         dname="${name%/*}"
         bname="${name##*/}"
         newname="${dname}/${bname//[[:space:]]/${0}}"
         if [[ -e "${newname}" ]]; then
            echo "Warning: file already exists: ${newname}" 1>&2
         else
            mv "${name}" "${newname}"
         fi
      done
  ' "${replace_char}" '{}' +
}

trspace rootdir _

이것은 조금 더 합니다.다운로드한 토렌트(특수 문자(비ASCII), 공백, 여러 개의 점 등)의 이름을 변경하는 데 사용합니다.

#!/usr/bin/perl

&rena(`find . -type d`);
&rena(`find . -type f`);

sub rena
{
    ($elems)=@_;
    @t=split /\n/,$elems;

    for $e (@t)
    {
    $_=$e;
    # remove ./ of find
    s/^\.\///;
    # non ascii transliterate
    tr [\200-\377][_];
    tr [\000-\40][_];
    # special characters we do not want in paths
    s/[ \-\,\;\?\+\'\"\!\[\]\(\)\@\#]/_/g;
    # multiple dots except for extension
    while (/\..*\./)
    {
        s/\./_/;
    }
    # only one _ consecutive
    s/_+/_/g;
    next if ($_ eq $e ) or ("./$_" eq $e);
    print "$e -> $_\n";
    rename ($e,$_);
    }
}

재귀 버전에 대한 쉬운 대안은 for 루프 범위를 단계별로 늘리는 것입니다(각 레벨의 하위 디렉터리 수에 관계없이 n개의 하위 레벨에 대해 n번).즉, 가장 바깥쪽 디렉터리에서 이를 실행합니다.

for f in *; do mv "$f" "${f// /_}"; done 

for f in */*; do mv "$f" "${f// /_}"; done 

for f in */*/*; do mv "$f" "${f// /_}"; done 

수행 중인 작업을 확인/이해하려면 위의 단계 전후에 다음을 실행합니다.

for f in *;do echo $f;done 

for f in */*;do echo $f;done 

for f in */*/*;do echo $f;done 

이 스크립트 주변에서 발견했습니다, 흥미로울 수도 있습니다 :)

 IFS=$'\n';for f in `find .`; do file=$(echo $f | tr [:blank:] '_'); [ -e $f ] && [ ! -e $file ] && mv "$f" $file;done;unset IFS

다음은 적절한 크기의 bash 스크립트 솔루션입니다.

#!/bin/bash
(
IFS=$'\n'
    for y in $(ls $1)
      do
         mv $1/`echo $y | sed 's/ /\\ /g'` $1/`echo "$y" | sed 's/ /_/g'`
      done
)

이렇게 하면 현재 디렉토리 내에서 파일만 찾고 이름을 변경할 수 있습니다.저는 이 별명을 가지고 있어요.

find ./ -name "* *" -type f -d 1 | perl -ple '$file = $_; $file =~ s/\s+/_/g; rename($_, $file);

저는 제 목적을 위해 하나를 만들 뿐입니다.참조용으로 사용할 수 있습니다.

#!/bin/bash
cd /vzwhome/c0cheh1/dev_source/UB_14_8
for file in *
do
    echo $file
    cd "/vzwhome/c0cheh1/dev_source/UB_14_8/$file/Configuration/$file"
    echo "==> `pwd`"
    for subfile in *\ *; do [ -d "$subfile" ] && ( mv "$subfile" "$(echo $subfile | sed -e 's/ /_/g')" ); done
    ls
    cd /vzwhome/c0cheh1/dev_source/UB_14_8
done

/files라는 폴더에 있는 파일의 경우

for i in `IFS="";find /files -name *\ *`
do
   echo $i
done > /tmp/list


while read line
do
   mv "$line" `echo $line | sed 's/ /_/g'`
done < /tmp/list

rm /tmp/list

이 문제에 대한 나의 해결책은 bash 스크립트입니다.

#!/bin/bash
directory=$1
cd "$directory"
while [ "$(find ./ -regex '.* .*' | wc -l)" -gt 0 ];
do filename="$(find ./ -regex '.* .*' | head -n 1)"
mv "$filename" "$(echo "$filename" | sed 's|'" "'|_|g')"
done

스크립트를 실행한 후 스크립트를 적용할 디렉터리 이름을 인수로 지정합니다.

아래 명령을 사용하여 파일 이름과 디렉터리 이름에 공백을 밑줄로 대체합니다.

find -name "* *" -print0 | sort -rz | \
  while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done

모든 공백을 대체하여 하나의 디렉토리에 있는 파일의 이름만 변경해야 하는 경우. 이 를 그런다 사명수있다니습용과 할 수 .rename.ul:

for i in *' '*; do rename.ul ' ' '_' *; done

실제로 펄에서 이름 바꾸기 스크립트를 사용할 필요가 없습니다.

find . -depth -name "* *" -execdir bash -c 'mv "$1" `echo $1 | sed s/ /_/g`' -- {} \;

언급URL : https://stackoverflow.com/questions/2709458/how-to-replace-spaces-in-file-names-using-a-bash-script