아래 스크립트는 현재 ^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
나는 이 펄 원 라이너를 선호합니다. '\cM'은 control-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