
아래 스크립트는 현재 ^M 문자( Ctrl+V+M
)를 제거합니다. 좀 장황한 것 같지만 ^I와 앞으로 볼 수 있는 다른 문자도 추가해야 합니다.
^I( )를 추가하는 더 쉬운 방법이 있나요 Ctrl+V+I
? 이것은 약 6개월 전에 2일간의 쉘 프로그래밍 과정을 수강한 후 제가 직접 작성한 첫 번째 스크립트입니다. 필요한 것보다 시간이 더 오래 걸리는지 잘 모르겠으므로 일반적인 팁도 알려주시면 감사하겠습니다.
#!/bin/bash
echo "$# item(s) to review."
question='Do you want to remove the ^M characters?'
for file
do
if grep "^M" "$file" >> /dev/null 2> /dev/null
then
echo "$file contains special characters"
echo $question
read answer
if [[ "$answer" == [yY] ]]
then
cat "$file" | sed "s/^M//" > "$file.safe"
echo "Special characters have been removed and $file.safe has been created."
elif [[ "$answer" == [yY][eE][sSaA]* ]]
then
cat "$file" | sed "s/^M//" > "$file.safe"
echo "Special characters have been removed and $file.safe has been created."
else
echo "Special characters have NOT been removed."
fi
elif [[ -d $file ]]
then
echo "$file is a directory"
else
echo "No special characters in $file"
fi
done
답변1
확실히 필요한 것보다 훨씬 더 오래 걸렸습니다. 당신에게 필요한 것은tr
유용, 스크립트에 인수로 전달된 파일에 대해 작동하는 루프 및 리디렉션이 포함됩니다.
#!/bin/sh
for file do
tr -d '\r\t' <"$file" >"$file.safe"
done
옵션을 사용하여 지정된 문자를 삭제 -d
합니다 tr
. 제거할 문자는 옵션이 아닌 첫 번째 인수로 함께 전달됩니다. 백슬래시 이스케이프를 사용하여 \n
개행(^J), \r
캐리지 리턴(^M), \t
탭(^I) 등 특수 문자를 나타낼 수 있습니다.
사용자에게 묻는 코드는 말이 안 되기 때문에 복사하지 않았습니다. 어쨌든 디렉토리는 리디렉션 오류를 일으키고 디렉토리를 일반 파일로 처리하는 것과 같은 무의미한 작업을 실제로 요청하지 않는 것이 호출자의 임무이므로 해당 부분도 건너뛰었습니다.
원본 파일을 바꾸려면 임시 파일에 쓴 다음 결과를 제자리로 옮깁니다.
#!/bin/sh
for file do
tmp="$(TMPDIR=$(dirname -- "$file") mktemp)"
tr -d '\r\t' <"$file" >"$tmp" && mv -f -- "$tmp" "$file"
done
임시 파일 이름은 mktemp
스크립트를 더욱 강력하게 만들기 위해 구성됩니다. 파일이 포함된 디렉터리에 대한 쓰기 액세스 권한이 있는 한 기존 파일을 덮어쓸 위험 없이 작동합니다. 다른 데이터를 삽입하려고 시도하는 다른 사용자가 해당 디렉토리에 쓸 수 있더라도(참조 자료의 잠재적인 문제 /tmp
) 안전합니다.
mv
이 명령은 호출이 성공한 경우에만 호출되므로 tr
실패해도 데이터가 손실될 위험이 없습니다(예: 디스크가 가득 찬 경우).tr
파일을 특수 문자가 포함되지 않은 동일한 새 파일로 바꾸는 것을 방지하려면 다음 두 가지 방법이 있습니다.
특수 문자를 먼저 확인할 수 있습니다. 이를 수행하는 방법에는 여러 가지가 있습니다. 한 가지 방법은 특수 문자를 제외한 모든 문자를 제거하고 결과 문자 수를 계산하는 것입니다. 최적화로서
head -c 1
특수 문자가 상단 근처에서 발견되면 전체 파일을 검토할 필요가 없도록 파이프하십시오. 이렇게 하면 할 일이 없으면 개수는 0이고 그렇지 않으면 1입니다.if [ "$(tr -dc '\r\t' <"$file" | head -c 1 | wc -c)" -ne 0 ]; then tr -d '\r\t' <"$file" >"$tmp" && mv -f -- "$tmp" "$file" fi
변환한 후 원본 버전과 동일한지 확인할 수 있습니다. 일반적으로 파일이 이미 원하는 상태에 있는 경우 속도가 느려질 수 있습니다. 반면, 이 기술은 파일이 원하는 상태인지 판단하기가 쉽지 않은 상황에 적합합니다.
tr -d '\r\t' <"$file" >"$tmp" && if cmp -s "$tmp" "$file"; then rm -- "$tmp" else mv -f -- "$tmp" "$file" fi
답변2
스크립트 주위에 루프를 넣을 수 있습니다. 그래서:
for c in "^I" "^M"; do
for file; do
if grep "$c" "$file"; then
...
etc.
...
fi
done
done
답변3
나는 이 Perl One 라이너를 선호합니다. '\cM'은 제어 M 문자입니다. 원본 파일은 ".bak" 확장자로 백업됩니다. 이 확장은 귀하가 선택할 수 있습니다.
perl -i.bak -pe 's/\cM//g;' file(s)
제거할 문자 유형을 사용하는 예입니다. 괄호 안에서 perl은 control-I와 control-M을 찾아서 제거합니다. 하지만 아직 구체적으로 테스트하지는 않았습니다.
perl -i.bak -pe 's/[\cM\cI]//g;' files(s)
답변4
사용에 대해 생각해 본 적이 있습니까?
tr -d .....<characterlist>....
예를 들어 인쇄할 수 없는 문자를 모두 제거하고 다른 파일에 넣으세요.
cat filename | tr -cd '[:print:]' >/tmp/x.out
응용 프로그램에 맞게 문자 목록을 수정하십시오. tr
자세한 내용은 매뉴얼 페이지를 참조하십시오.
정규식 범위가 허용되기 때문에 이는 또한 좋습니다.
echo '\001\002\003\004' | tr -d '[\001-\003]' | od -c