파일로 가득 찬 디렉토리가 있습니다. 내 목표는 파일 시작 부분에 텍스트를 추가하는 것입니다. 각 파일의 시작 부분에 있는 텍스트는 동일합니다. 이게 내 시도야
#!/bin/bash
for file in `find . -type f -executable`;do
sed '/\#!/bin/bash\/a Hello Word'
done
내 스크립트는 충돌만 발생합니다.
답변1
#!/bin/bash for file in `find . -type f -executable`;do sed '/\#!/bin/bash\/a Hello Word' fi done
이 스크립트에는 많은 문제가 있습니다.
첫째, fi
해당 if
.
스타일상( fi
줄을 제거한 후) 앞의 빈 줄을 제거 done
하고 그 앞에 공백을 추가합니다 do
. 그러나 이것은 상대적으로 사소한 일이다.
이제 모범 사례에 따르면 권장되는 최신 형식 대신 백틱을 사용하여 명령을 대체합니다 $(...)
. 백틱에 대한 지원은 순전히 역사적인 이유로 권장되지 않습니다.
출력을 반복하기 때문에 견고성 문제가 있습니다 find
. 이는 매우 나쁜 생각이고 완전히 불필요한 것입니다. 공백이나 특수 문자가 포함된 파일 이름에서 스크립트가 중단됩니다. 바라보다:
스크립트를 이식 가능하게 하려면 가능하면 POSIX에 지정된 기능을 고수해야 합니다. 특히 -executable
가장 중요한 find
것은POSIX가 지정되지 않았습니다.. 대신 사용해 보세요 -perm +700
.
또한 이식성 영역에서 a
다음 \<newline>
순서 없이 Sed()를 사용하는 GNU Sed의 "추가" 명령은 작동하지만 표준은 아닙니다.
file
루프 의 변수를 각 파일의 이름으로 차례로 설정합니다 ( for
파일 이름에 특수 문자나 공백이 없다고 가정하면 변수에 file
다음이 포함됩니다).아니요파일 이름), 하지만 실제로는사용변수 file
.
Sed 명령은 실행할 파일을 제공하지 않으므로 표준 입력에서 실행을 시도합니다. 따라서 스크립트를 실행하면 입력을 기다립니다.
Sed 스크립트 자체가 올바르지 않으며 작동할 파일 이름이 없다는 사실과 아무 관련이 없습니다.
/
정규 표현식(가장 일반적임)에서 구분 기호 로 사용하는 경우 /
정규 표현식에서 해당 문자가 나오는 모든 항목을 백슬래시로 이스케이프 처리해야 합니다. 명령의 유일한 부분은 정규식으로 읽히고 /\#!/
나머지 부분(이로 시작하는 부분 bin
)은 Sed 명령으로 해석됩니다.
대신, 일반적인 해결책은 각각을 교체하는 것입니다./
다른최종 정규식 구분 기호보다 \/
(이스케이프된 것 같습니다.오직마지막 슬래시는아니요탈출했습니다. )
하나 있다Sed의 잘 알려지지 않은 기능,여기서 이것을 유리하게 활용할 수 있습니다. 어느백슬래시나 개행 문자 이외의 문자는 슬래시뿐만 아니라 정규식 구분 기호로 사용할 수 있습니다. 따라서 이를 /#!\/bin\/bash/
Sed 주소 로 사용하는 대신 동등한 주소를 사용할 수 있습니다.\:#!/bin/bash:
이제 위의 모든 사항을 처리했다면 작동하는 스크립트가 생겼을 것입니다. 아마 당신이 원하는 대로 되지 않을 거예요생각하다그렇게 해야 하지만 실제로는 그렇게 될 것입니다.뭔가를 해라. 이러한 스크립트는 다음과 같습니다.
#!/bin/bash
find . -type f -perm -700 -exec sed '\:#!/bin/bash:a\
Hello World' {} +
이 스크립트는 무엇을 합니까? 현재 디렉터리에서 실행 가능 비트(소유자)가 설정된 모든 파일을 반복적으로 검색하고, 이러한 각 파일에 대해 전체 파일을 인쇄하고 Hello World
text 가 포함된 줄 뒤에 텍스트를 추가합니다 #!/bin/bash
.
sed는 실제로는 아닙니다디자인됨파일을 제자리에서 편집하는 데 사용됩니다. 스트림 편집기입니다. GNU Sed에서는 스위치를 사용하여 파일을 편집할 수 있지만 -i
저는 그냥 다음을 사용하겠습니다.표준 도구ex
파일 편집에 사용됩니다.
하지만 여기에는 다른 것이 있습니다. Bash 스크립트에 해당 줄을 추가 하려는 경우 유효한 명령 이름이 아니기 Hello World
때문에 실제로 아무 작업도 수행되지 않습니다 . Hello
아마도 당신이 원하는 것은인쇄Bash 스크립트에 "Hello World"라는 텍스트를 추가하는 것이 echo "Hello World
합리적일 수 있습니다 .
이제 우리는 귀하의 스크립트가 무엇인지 더 정확하게 설명하고 싶습니다.~해야 한다해.
최종 스크립트
따라서 이 스크립트의 사양에 대한 보다 정확한 설명은 다음과 같습니다.
- 이 스크립트는 소유자에 대해 실행 가능한 비트가 설정된 현재 디렉터리(또는 재귀적으로 모든 하위 디렉터리)에서 모든 일반 파일을 찾아야 합니다.
- 이러한 각 파일에 대해 스크립트는 파일의 첫 번째 줄이 문자열과 정확히 동일한지 확인해야 합니다
#!/bin/bash
. - 정확한 첫 번째 줄이 있는 파일의 경우에만 스크립트는
echo "Hello World"
파일의 첫 번째 줄 뒤에 정확한 텍스트를 삽입하고 그 뒤에 개행 문자를 삽입해야 합니다. (이 변경 사항은 표준 출력으로 인쇄하기보다는 파일에 저장해야 합니다.)
다음은 POSIX 도구와 기능만 사용하여 정확한 사양을 준수하는 스크립트입니다.
#!/bin/sh
find . -type f -perm -700 -exec sh -c '
for f
do
head -n 1 "$f" | grep -qFx "#!/bin/bash" &&
printf "%s\n" "1a" "echo \"Hello World\"" . x | ex "$f"
done
' find-sh {} +
답변2
무엇을 달성하고 싶나요? 실행 가능한 스크립트를 찾으려면 다음 명령을 사용하십시오.
find . -type f -perm /u+x,g+x,o+x | while read file
do
filename=$(echo ${file} | awk -F/ '{print $NF}')
echo "File Name : ${filename}"
done
Shebang 줄 뒤에 Hello World를 추가하려고 하면 sed 명령은 다음과 같아야 합니다.
sed '/\#!/bin/bash/a Hello Word' ${file}
파일 자체를 변경하려면 sed 명령에 -i를 추가하세요.
답변3
find . -type f -executable -exec sed '/^#!\/bin\/bash/a Hello World' {} \;