파일 이름의 점을 바꾸고 밑줄로 대체하여 확장자를 변경하지 않고 그대로 두는 데 사용하려는 bash 스크립트가 있습니다(btw, 저는 Centos 6을 사용하고 있습니다). 아래 출력에서 볼 수 있듯이 교체해야 할 점이 있을 때 스크립트가 작동하지만 유일한 점이 확장명인 경우 스크립트는 파일을 무시하는 대신 파일 이름을 바꾸려고 계속 시도합니다. 내가 이 문제를 어떻게 더 잘 처리해야 하는지 지적할 수 있는 사람이 있나요? 도와주셔서 감사합니다.
내 (잘못된) 스크립트:
#!/bin/bash
for THISFILE in *
do
filename=${THISFILE%\.*}
extension=${THISFILE##*\.}
newname=${filename//./_}
echo "mv $THISFILE ${newname}.${extension}"
#mv $THISFILE ${newname}.${extension}
done
입력 예:
1.3MN-Pin-Eurotunnel-Stw505.51.024-EGS-130x130.jpg
Wear-Plates.jpg
산출:
mv 1_3MN-Pin-Eurotunnel-Stw505_51_024-EGS1-130x130.jpg 1_3MN-Pin-Eurotunnel-Stw505_51_024-EGS1-130x130.jpg
mv Wear-Plates_jpg.Wear-Plates_jpg Wear-Plates_jpg.Wear-Plates_jpg
답변1
나는 이 프로그램이 당신이 원하는 것을 할 것이라고 믿습니다. 테스트해 본 결과 몇 가지 흥미로운 경우(예: 확장이 전혀 없는 경우)에서 작동합니다.
#!/bin/bash
for fname in *; do
name="${fname%\.*}"
extension="${fname#$name}"
newname="${name//./_}"
newfname="$newname""$extension"
if [ "$fname" != "$newfname" ]; then
echo mv "$fname" "$newfname"
#mv "$fname" "$newfname"
fi
done
직면하게 되는 주요 문제는 확장 프로그램이 ##
원하는 작업을 수행하지 않는다는 것입니다. 나는 항상 bash의 쉘 매개변수 확장이 일종의 흑마법이라고 생각했습니다. 매뉴얼의 설명은 완전히 명확하지 않으며 확장 기능의 작동 방식에 대한 지원 예제가 부족합니다. 그들은 또한 매우 신비합니다.
sed
개인적으로 저는 원하는 방식으로 이름을 조정하는 작은 스크립트를 작성하거나 perl
전체 작업을 수행하는 작은 스크립트를 작성합니다. 대답한 다른 사람도 이런 접근 방식을 취했습니다.
제가 지적하고 싶은 또 다른 점은 인용문을 사용한다는 것입니다. 나는 쉘 스크립트로 무엇인가를 할 때마다 사람들에게 인용할 때 매우 조심하라고 상기시킵니다. 쉘 스크립트에서 문제의 가장 큰 원인은 쉘이 해석해서는 안되는 것을 해석한다는 것입니다. 그리고 인용 규칙은 명백하지 않습니다. 나는 이 쉘 스크립트에 인용 문제가 없다고 생각합니다.
답변2
사용합니다 for thisfile in *.*.*
(즉, 이름에 두 개 이상의 점이 포함된 루프 파일). 변수를 인용하고 이를 사용하여 --
아래와 같이 옵션의 끝을 표시 하십시오.mv -- "$thisfile" "$newname.$extension"
zsh를 사용하세요.
autoload -U zmv
zmv '(*).(*)' '${1//./_}.$2'
답변3
이건 어때:
perl -e '
@files = grep {-f} glob "*";
@old_files = @files;
map {
s!(.*)\.!$1/!;
s!\.!_!g;
s!/!.!
} @files;
rename $old_files[$_] => $files[$_] for (0..$#files)
'
면책 조항: 먼저 가상 디렉터리에서 시도해 보세요. 아직 테스트하지 않았습니다!
답변4
이 버전을 사용하면 오른쪽부터 시작하여 유지하려는 포인트 수를 명시적으로 선택할 수 있습니다.
또한 점 이외의 문자를 대체 및/또는 제거하며 대체 문자는 -
밑줄이 아니지만 쉽게 변경할 수 있습니다.
#!/bin/sh
# Rename files by replacing Unix-unfriendly characters.
usage () {
cat <<EOF
usage: $0 [OPTIONS] [--] [FILE [FILE...]]
Rename files by replacing Unix-unfriendly characters.
Options:
-p N preserve last N dots in filename, or keep all
dots if N < 0 (default: 1)
--help show this help and exit
EOF
}
error () {
printf "%s\n" "$1" 1>&2
}
delete_chars="()[]{}*?!^~%\\\<>&\$#|'\`\""
replace_chars=" _.,;-"
unixify_string () (
printf '%s\n' "$1" \
| tr -d "$delete_chars" \
| tr -s "$replace_chars" - \
| to_lower \
| sed 's/^-\(.\)/\1/; s/\(.\)-$/\1/'
)
to_lower () {
sed 's/.*/\L&/'
}
split () (
# split '.x.x.x.x' 0 -> '/x.x.x.x.x
# split '.x.x.x.x' 1 -> '/x.x.x.x/x
# split '.x.x.x.x' 2 -> '/x.x.x/x/x
# split '.x.x.x.x' -1 -> '/x/x/x/x/x
nf=$(printf '%s\n' "$1" | tr -d -C . | wc -c)
if [ $2 -lt 0 ]; then
keep=0
else
keep=$((nf-$2))
fi
IFS=. i=0 out= sep=
for part in $1; do
out="$out$sep$part"
if [ -z "$out" -o $i -ge $keep ]; then
sep=/
else
sep=.
fi
i=$(($i+1))
done
printf '%s\n' "$out"
)
unixify () (
IFS=/ out= sep=
for part in $(split "$1" $2); do
out="$out$sep$(unixify_string "$part")"
sep=.
done
printf '%s\n' "$out"
)
rename_maybe () (
dir="$(dirname "$1")"
name="$(basename "$1")"
newname="$(unixify "$name" $2)"
if [ "$newname" != "$name" ]; then
mv -i "$dir/$name" "$dir/$newname"
fi
)
# command line arguments
short_opts=p:
long_opts=help
args="$(LC_ALL=C getopt -n "$0" -s sh -o $short_opts -l $long_opts -- "$@")"
if [ $? -eq 0 ]; then
eval set -- "$args"
else
exit 1
fi
p=
while [ $# -gt 0 ]; do
case "$1" in
--help)
usage; exit 0 ;;
-p)
p="$2"; shift
if ! [ "$p" -eq "$p" ] 2> /dev/null; then
error "$0: option requires integer argument -- 'p'"
exit 1
fi ;;
--)
shift; break ;;
-*)
error "$0: illegal option -- '$1'"
exit 1 ;;
*)
break
esac
shift
done
# defaults
p=${p:-1}
# echo p=$p
# echo "$@"
# echo n=$#
# exit
if [ $# -lt 1 ]; then
error "$0: required non-option argument missing"
exit 1
fi
for file in "$@"; do
rename_maybe "$file" $p
done