이것은 작동합니다:
sudo sed 's/good times/bad times/' Chapter1.html > output/Chapter1.html
이것은 작동하지 않습니다:
sudo sed 's/good times/bad times/' Chapter*.html > output/Chapter*.html
이것도 작동하지 않습니다.
sudo sed 's/good times/bad times/' *.html > output/*.html
50개의 챕터가 있으므로 sed에서 와일드카드를 사용하도록 할 수 있나요?
답변1
다른 사람들이 언급했듯이 여기에는 와일드카드뿐만 아니라 루프가 필요합니다.
예를 들어, for
쉘 루프를 사용하여 이를 수행하려면 다음을 수행하십시오.
for f in ./*.html; do
sed 's/good times/bad times/' "$f" > "output/$f"
done
그러면 변수가 f
각 .html 파일 이름으로 설정되어 루프가 반복될 때마다 루프 내에서 코드가 실행됩니다. 단지 ../*.html
*.html
f
명령문 자체에는 for
(값을 설정하는 곳이기 때문에) 간단한 단어가 있지만 $f
변수가 루프 내부에서 사용되는 경우(확장되는 곳이기 때문에)에 주목하세요.
;
변수 확장은 공백 문자나 쉘에 특별한 의미가 있는 기타 문자(예 : , &
, >
및 기타 여러 문자) 가 포함된 경우 스크립트가 손상되지 않도록(또는 더 나쁜 경우) 큰따옴표로 묶습니다 . 변수를 사용할 때 변수를 인용하지 않는 것이 아마도 쉘 스크립트 오류의 가장 큰 원인일 것입니다. 바라보다공백이나 기타 특수 문자 때문에 쉘 스크립트가 멈추는 이유는 무엇입니까?그리고$VAR 대 ${VAR} 및 인용 여부이유를 알아보세요.
원하는 변수 이름을 사용할 수 있습니다.
for Chapter in ./*.html; do
sed 's/good times/bad times/' "$Chapter" > "output/$Chapter"
done
또한 주목할 가치가 있는 것은: 디렉토리에 .html 파일이 없으면 먼저 이 옵션을 활성화하지 않는 한 쉘은 f
(또는 Chapter
)을 리터럴 문자열로 설정합니다 . 에서 :*.html
nullglob
shopt -s nullglob
man bash
nullglob
설정된 경우, bash는 어떤 파일과도 일치하지 않는 패턴(
위의 경로 이름 확장 참조)이 자신이 아닌 빈 문자열로 확장되도록 허용합니다.
그런데 저는 파일 이름이 명령줄 옵션 중 하나로 해석되는 것을 방지하기 위해 루프 ./*.html
와 함께 이것을 사용하고 있습니다.for
*.html
sed
주석에서 @StéphaneChazelas가 언급했듯이 -e
디렉토리에 시작하고 끝나는 파일 이름이 있으면 sed는 이를 실행할 sed 스크립트로 해석합니다. #.html
이런 일이 일어날 가능성은 거의 없지만(배설물과 악의도 마찬가지입니다), 가능한 한 방어적으로 프로그래밍하는 것이 가장 좋습니다.
./*.html
예를 들어 sed 대신 인수를 사용하면 파일 이름이 지정 -e1,$d
되므로 -e1,$d#.html
(완벽하게 유효한 파일 이름) 인수가 ./-e1,$d
sed의 명령줄 옵션 중 하나로 해석되지 않는 것을 볼 수 있습니다. sed 옵션이 에 없습니다 ./
.
또한: $f
로 시작하기 때문에 ./
파일 이름과 같은 출력은 foo.html
으로 리디렉션됩니다 . 경로에 추가 요소가 있어도 여전히 동일한 대상으로 확인되므로 output/./foo.html
이는 완전히 문제가 되지 않습니다 . ./
우스꽝스러운 일조차 output/./././[a million more ./s]/foo.html
그저output/foo.html
GNU sed(Linux의 표준 sed) 또는 (거의?) 최신 버전의 sed를 사용하는 경우 다음을 --
사용하여 옵션 인수의 끝을 나타낼 수 있습니다.
for f in *.html; do
sed 's/good times/bad times/' -- "$f" > "output/$f"
done
아니면 둘 다 수행하세요.
for f in ./*.html; do
sed 's/good times/bad times/' -- "$f" > "output/$f"
done
답변2
쉘은 명령줄에서 와일드카드 문자를 확장하지만 실행 중인 명령은 이를 볼 수도 없고 어떻게 해야 할지 알지도 못합니다.
따라서 파일이 있고 a.html
b.html
실행 output/b.html
output/c.html
하면
sed ... *.html > output/*.html
실제로 실행할 명령은 다음과 같습니다.
sed ... a.html b.html > output/b.html output/c.html
이는 구문 오류(두 파일로 리디렉션할 수 없음)이며 아마도 원하는 것이 아닐 것입니다.
여기서 해결책은 for 루프를 사용하고 *를 루프의 인덱스 변수로 바꾸는 것입니다. 파일 이름에 공백이 있는 경우 일부 인용이 필요합니다. 이 질문의 사본에는 이를 올바르게 수행하는 방법에 대한 많은 예가 있습니다.
답변3
파일이 포함된 작업 디렉토리에 있다고 가정하면 다음을 사용할 수 있습니다.find
$ find . -name 'Chapter*' -exec sed 's/good times/bad times/woutput/{}' {} 2> /dev/null \;