라는 쉘 스크립트를 작성해야 합니다 chExt.sh
. 파일 확장자를 허용한 다음 여러 파일을 허용합니다. 그런 다음 파일 확장자를 변경하거나 파일이 존재하지 않는다고 선언해야 합니다.
./chExt.sh txt ocelot.cpp ../otherFolder/file.H cat.dog.TXT king cobra.dat
자동 테스터 테스트의 일반적인 아이디어입니다. 문제는 이름에 공백이 있는 파일을 처리하는 방법을 전혀 모른다는 것입니다.
내 코드는 다음과 같습니다
newExt="$1"
shift
for x in $*
do
fileName="$x"
if test -f "$fileName";
then
name=$(echo "$fileName" | rev | cut -f 2- -d '.' | rev)
newName="$name.$newExt"
if test "$newName" != "$fileName";
then
mv "$x" "$newName"
fi
else
echo "$fileName: No such file"
fi
done
답변1
파일 이름을 인용하지 않으면 쉘은 이것이 두 개의 인수( 및 ) foo bar.txt
가 아니라 하나의 인수 라는 것을 알 수 없습니다 . 따라서 다음과 같이 스크립트를 호출해야 합니다.foo
bar.txt
./chExt.sh txt ocelot.cpp ../otherFolder/file.H cat.dog.TXT "king cobra.dat"
다음 문제는 변수가 확장되면 결과 값이빈 공간에서 분할(또는 $IFS
변수에 설정된 값). 따라서 for i in $*
을 쓰면 $*
공간이 확장되고 분할됩니다. 그래서 그것은 한 번의 반복과 다음 반복이 됩니다 $i
. 해결 방법은 확장하려는 변수가 분할되지 않도록 인용하는 것입니다.king
cobra.txt
이는 다음 질문으로 이어집니다.$*
사이의 차이$@
. 사용된 경우 "$*"
인수는 모두 하나의 긴 문자열로 처리됩니다.
$ cat foo.sh
#!/bin/sh
for i in "$*"; do
echo "$i"
done
$ foo.sh foo "bar baz"
foo bar baz
위 내용을 다음과 비교해보세요.
#!/bin/sh
for i in "$@"; do
echo "$i"
done
$ foo.sh foo "bar baz"
foo
bar baz
보시다시피 를 사용하면 "$@"
예상되는 효과가 있으며 공백이 있는 인수를 포함하여 각 입력 인수가 개별적으로 처리됩니다.
마지막으로 스크립트는 -
옵션에 해당하는 문자와 다음으로 시작하는 파일 이름도 차단합니다(예: echo
이름이 지정된 파일을 사용해 보세요). -new
확장을 제거하는 더 좋은 방법은 셸의 기본 확장을 사용하는 것입니다.문자열 조작 함수. 변수 끝에서 ${var%.*}
a 및 0개 이상의 문자와 일치하는 가장 짧은 문자열을 제거합니다 . .
즉, 확장입니다. 그런 다음 다음으로 시작하는 파일 이름도 처리할 수 있도록 옵션의 끝과 인수의 시작을 나타내기 위해 to --
를 추가 해야 합니다 (가이드 10 참조).mv
-
여기).
따라서 개선되고 작동하는 스크립트 버전은 다음과 같습니다.
#!/bin/sh
newExt="$1"
shift
for fileName in "$@"
do
if test -f "$fileName";
then
# name=$(echo "$fileName" | rev | cut -f 2- -d '.' | rev)
name=${fileName%.*}
newName="$name.$newExt"
if test "$newName" != "$fileName";
then
mv -- "$fileName" "$newName"
fi
else
printf '%s: No such file\n' " $fileName"
fi
done
추가 자료:
답변2
"$*"
및 의 또 다른 주목할만한 속성은 "$@"
셸 인수의 현재 컬렉션인 셸 배열을 나타낸다는 것입니다. 이는 set
내장 함수를 통해 변경할 수 있지만, 더 일반적으로 내장 배열 함수의 기본값은 배열을 포함한 배열에서 작동하는 것입니다 for
.
: "${2?no file arguments!}"
for x
do if [ "${2+:}" ]
then set ".$1"
else [ ".${x##*.}" != "$1" ] &&
[ -f "$x" ] &&
mv -- "$x" "${x%.*}$1"
fi
done
이는 스크립트가 수행하는 작업과 매우 유사합니다. echo
일반 파일이 아닌 인수에서는 작동 하지 않는다는 점에서 약간 다릅니다 . 그러나 나는 당신이 거기서 하고 있다고 생각하는 것을 하고 있는지 확신할 수 없습니다. 당신의 주장이 존재하는지, 접근 가능한지,일반 파일, 그러나 echo
stdout에 다음과 같은 메시지를 보내고 있습니다.매개변수: 해당 파일이 없습니다.. Unix 계열 시스템에서는 모든 것이 파일입니다. 파이프는 파일이고, 디렉터리는 파일이고, 장치는 파일입니다. 따라서 귀하의 테스트는 귀하의 정보와 일치하지 않습니다. 게다가, mv
존재하지 않는 파일을 이동하라고 요청하면 메시지가 자동으로 인쇄되고 stderr에도 인쇄됩니다.
내가 알아차린 또 다른 점은 새 이름이 이전 이름과 같은지 테스트하고 있다는 것입니다. 이는 mv
파일 자체를 이동하는 것에 대한 불만을 피하기 위한 것이라고 생각합니다. 공교롭게도 mv
이 상황을 침묵시킬 수 있는 옵션이 있습니다.
나는 다음과 같이 당신의 일을 할 것 같아요 :
: "${2?no file arguments!}"
for x
do [ "${2+:}" ] &&
set -- ".$1" && continue
set -- "${x%.*}$1" "$1"
{ [ -e "$1" ] && printf "%s: exists!\n" "$1"; } ||
{ ! [ -f "$x" ] && printf "%s: not a regular file.\n" "$x"; } ||
mv -f -- "$x" "$1"
shift
done >&2