Bash는 버전 번호를 제거하기 위해 일련의 패키지 이름을 어떻게 바꿀 수 있습니까? 나는 모두 주위 놀겠다는 거 봤는데 expr와 %%아무 소용.
예 :
Xft2-2.1.13.pkg 된다 Xft2.pkg
jasper-1.900.1.pkg 된다 jasper.pkg
xorg-libXrandr-1.2.3.pkg 된다 xorg-libXrandr.pkg
Bash는 버전 번호를 제거하기 위해 일련의 패키지 이름을 어떻게 바꿀 수 있습니까? 나는 모두 주위 놀겠다는 거 봤는데 expr와 %%아무 소용.
예 :
Xft2-2.1.13.pkg 된다 Xft2.pkg
jasper-1.900.1.pkg 된다 jasper.pkg
xorg-libXrandr-1.2.3.pkg 된다 xorg-libXrandr.pkg
답변:
bash의 매개 변수 확장 기능을 사용할 수 있습니다.
for i in ./*.pkg ; do mv "$i" "${i/-[0-9.]*.pkg/.pkg}" ; done
공백이있는 파일 이름에는 따옴표가 필요합니다.
rename "s/-[0-9.]*//" *.pkg
모든 파일이 동일한 디렉토리에 있으면 시퀀스
ls |
sed -n 's/\(.*\)\(-[0-9.]*\.pkg\)/mv "\1\2" "\1.pkg"/p' |
sh
당신의 일을 할 것입니다. 나오지 명령의 시퀀스를 생성합니다 MV , 명령하는 할 수 있습니다 후 껍질에 파이프. | sh명령이 원하는 작업을 수행하는지 확인 하려면 먼저 후행없이 파이프 라인을 실행하는 것이 가장 좋습니다 .
여러 디렉토리를 반복하려면 다음과 같이 사용하십시오.
find . -type f |
sed -n 's/\(.*\)\(-[0-9.]*\.pkg\)/mv "\1\2" "\1.pkg"/p' |
sh
에가 있습니다 나오지 순서를 그룹화 정규 표현식은 앞에 백 슬래시 브라켓입니다, \(그리고 \)오히려 하나의 브라켓보다, (하고 ).
ls스크립트에서 사용하지 마십시오 . 첫 번째 다양성은 printf '%s\n' * | sed ...창의력 으로 얻을 수 있으며 약간의 창의력으로 제거 할 수도 sed있습니다. Bash 는 리터럴 쉘 메타 문자를 포함하는 파일 이름이있는 경우 유용 할 수 printf있는 '%q'형식 코드를 제공합니다 .
다음과 같이 할 것입니다.
for file in *.pkg ; do
mv $file $(echo $file | rev | cut -f2- -d- | rev).pkg
done
모든 파일이 현재 디렉토리에 있다고 가정합니다. 그렇지 않다면 위에서 Javier가 조언 한대로 find를 사용해보십시오.
편집 : 또한이 버전은 위의 다른 기능과 같이 bash 특정 기능을 사용하지 않으므로 더 많은 이식성을 얻을 수 있습니다.
다음은 현재 허용되는 답변 과 거의 동일한 POSIX 입니다. 이것은 ${variable/substring/replacement}Bourne 호환 쉘에서 사용할 수 있는 Bash 전용 매개 변수 확장을 교환합니다 .
for i in ./*.pkg; do
mv "$i" "${i%-[0-9.]*.pkg}.pkg"
done
매개 변수 확장 ${variable%pattern}은 variable일치하는 접미사가 pattern제거 된 값을 생성합니다 . ( ${variable#pattern}접두사 제거 도 있습니다 .)
-[0-9.]*오해의 소지가 있지만 수락 된 답변에서 하위 패턴 을 유지했습니다 . 정규식이 아니라 glob 패턴입니다. 따라서 "대시 뒤에 0 개 이상의 숫자 또는 점이 표시됨"을 의미하지 않습니다. 대신, "대시, 숫자 또는 점, 그 뒤에 오는 것"을 의미합니다. "anything"은 가장 긴 것이 아니라 가능한 가장 짧은 일치입니다. (배쉬 제공 ##하고 %%오히려 짧은보다, 가장 긴 접두사 나 접미사를 트리밍.)
sed* nix에서 사용할 수 있다고 가정 할 수 있지만 sed -nmv 명령 생성을 지원할 수 있을지 확신 할 수 없습니다 . ( 참고 : GNU 만이 작업을 sed수행합니다.)
그럼에도 불구하고 bash 내장 및 sed, 우리는 이것을 수행하기 위해 쉘 함수를 빠르게 채울 수 있습니다.
sedrename() {
if [ $# -gt 1 ]; then
sed_pattern=$1
shift
for file in $(ls $@); do
mv -v "$file" "$(sed $sed_pattern <<< $file)"
done
else
echo "usage: $0 sed_pattern files..."
fi
}
sedrename 's|\(.*\)\(-[0-9.]*\.pkg\)|\1\2|' *.pkg
before:
./Xft2-2.1.13.pkg
./jasper-1.900.1.pkg
./xorg-libXrandr-1.2.3.pkg
after:
./Xft2.pkg
./jasper.pkg
./xorg-libXrandr.pkg
mv은 (는) 대상 폴더를 자동으로 생성하지 않기 때문에 초기 버전의 sedrename.
상당히 작은 변경이므로 해당 기능을 포함하는 것이 좋습니다.
abspathbash에는이 빌드가 없기 때문에 유틸리티 함수 (또는 절대 경로)가 필요합니다.
abspath () { case "$1" in
/*)printf "%s\n" "$1";;
*)printf "%s\n" "$PWD/$1";;
esac; }
일단 우리는 새 폴더 구조를 포함하는 sed / rename 패턴에 대한 대상 폴더를 생성 할 수 있습니다.
이렇게하면 대상 폴더의 이름을 알 수 있습니다. 이름을 바꿀 때 대상 파일 이름에 사용해야합니다.
# generate the rename target
target="$(sed $sed_pattern <<< $file)"
# Use absolute path of the rename target to make target folder structure
mkdir -p "$(dirname $(abspath $target))"
# finally move the file to the target name/folders
mv -v "$file" "$target"
다음은 전체 폴더 인식 스크립트입니다.
sedrename() {
if [ $# -gt 1 ]; then
sed_pattern=$1
shift
for file in $(ls $@); do
target="$(sed $sed_pattern <<< $file)"
mkdir -p "$(dirname $(abspath $target))"
mv -v "$file" "$target"
done
else
echo "usage: $0 sed_pattern files..."
fi
}
물론 특정 대상 폴더가 없을 때도 여전히 작동합니다.
모든 노래를 폴더에 넣으려면 다음과 ./Beethoven/같이 할 수 있습니다.
sedrename 's|Beethoven - |Beethoven/|g' *.mp3
before:
./Beethoven - Fur Elise.mp3
./Beethoven - Moonlight Sonata.mp3
./Beethoven - Ode to Joy.mp3
./Beethoven - Rage Over the Lost Penny.mp3
after:
./Beethoven/Fur Elise.mp3
./Beethoven/Moonlight Sonata.mp3
./Beethoven/Ode to Joy.mp3
./Beethoven/Rage Over the Lost Penny.mp3
이 스크립트를 사용하여 폴더에서 단일 폴더로 파일 이동 :
일치하는 모든 파일을 모아서 현재 폴더에 저장한다고 가정하면 다음과 같이 할 수 있습니다.
sedrename 's|.*/||' **/*.mp3
before:
./Beethoven/Fur Elise.mp3
./Beethoven/Moonlight Sonata.mp3
./Beethoven/Ode to Joy.mp3
./Beethoven/Rage Over the Lost Penny.mp3
after:
./Beethoven/ # (now empty)
./Fur Elise.mp3
./Moonlight Sonata.mp3
./Ode to Joy.mp3
./Rage Over the Lost Penny.mp3
정규 sed 패턴 규칙이이 스크립트에 적용되며 이러한 패턴은 PCRE (Perl 호환 정규식)가 아닙니다.
플랫폼에 따라 sed -r또는 둘 중 하나를 사용하여 확장 정규식 구문을 sed 할 수 있습니다 sed -E.
man re_formatsed 기본 및 확장 정규식 패턴에 대한 전체 설명은 POSIX 준수 를 참조하십시오 .
이름 바꾸기가 이런 종류의 작업에 사용하기에 훨씬 더 간단한 도구라는 것을 알았습니다. OSX 용 Homebrew에서 찾았습니다.
귀하의 예를 들면 다음과 같습니다.
rename 's/\d*?\.\d*?\.\d*?//' *.pkg
's'는 대체를 의미합니다. 양식은 s / searchPattern / replacement / files_to_apply입니다. 약간의 연구가 필요하지만 노력할만한 가치가있는 정규식을 사용해야합니다.
for및 sed등 괜찮지 만, 그냥 사용에 더 빨리 더 간단하고 rename자신은 종종이 일을 찾을 경우.
rename명령 이있는 것은 아닙니다 . 또한 일부는 기능, 구문 및 / 또는 옵션이 다른 다른 rename 명령을 사용합니다. 이것은 rename꽤 인기있는 Perl처럼 보입니다 . 그러나 대답은 이것을 정말로 명확히해야합니다.
이것은 가정에서 작동하는 것 같습니다
.pkg를 떼어 낸 다음-..
for x in $(ls); do echo $x $(echo $x | sed 's/\.pkg//g' | sed 's/-.*//g').pkg; done
-e. 예 sed -e 's/\.pkg//g' -e 's/-.*//g'.
동일한 폴더에서 *.txt이름을 바꿀 여러 파일이 있습니다 .sql. 아래는 나를 위해 일했습니다.
for i in \`ls *.txt | awk -F "." '{print $1}'\` ;do mv $i.txt $i.sql; done
이 답변에 감사드립니다. 나는 또한 어떤 종류의 문제가 있었다. .nzb.queued 파일을 .nzb 파일로 이동. 파일 이름에 공백과 기타 균열이 있었고 이것은 내 문제를 해결했습니다.
find . -type f -name "*.nzb.queued" |
sed -ne "s/^\(\(.*\).nzb.queued\)$/mv -v \"\1\" \"\2.nzb\"/p" |
sh
그것은 Diomidis Spinellis의 대답을 기반으로합니다.
정규식은 전체 파일 이름에 대해 하나의 그룹과 .nzb.queued 이전 부분에 대해 하나의 그룹을 만든 다음 셸 이동 명령을 만듭니다. 인용 된 문자열로. 이것은 이미 sed에 의해 수행되기 때문에 쉘 스크립트에서 루프를 생성하는 것을 방지합니다.
-n같은 방식으로 옵션을 해석하지 않습니다 .