많은 분들이 알고 있는 기본적인 리눅스 명령어지만, 옵션들을 조금 더 알게 된다면 더 유용하게 활용할 수 있는 것들을 정리해 보고자 합니다.
find
일반적으로 파일 이름의 전체나 일부로 검색을 할 때 많이들 사용하시죠?
find . -name "*some_name*"
파일 이름 뿐만 아니라 파일 경로에서 매칭되는 것을 찾을 수도 있습니다.
find . -path "*some_path*"
find . -path "*some_path/some_file*"
혹은 파일 유형으로 찾을 수도 있습니다.
find . -type f # 일반 파일 검색
find . -type d # 디렉토리 검색
find . -type l # 심볼릭 링크 검색
파일 크기 기준으로 찾거나,
find . -size +300k # 크기가 300k 이상인 파일 검색
파일 생성(수정) 시간 기준으로 찾을 수도 있구요.
find . -ctime +1 # 하루 이전에 생성(수정)된 파일 검색
find . -ctime -1 # 하루 이내에 생성(수정)된 파일 검색
특정 파일보다 더 나중에 생성(or 수정)된 파일을 찾을 수도 있습니다. 저는 주로 어떤 작업을 하고 나서 이로 인해 변경된 파일이 무엇이 있을지 찾아보는 용도로 사용합니다.
touch a
touch b # do some jobs
find . -newer a
b
반대로 찾으시려면? not을 붙여주면 되겠지요.
find . ! -newer a
위 모든 옵션들은 and, or 로 묶어서 검색할 수도 있습니다. 이처럼요.
find . -name "*some_name*" -a -type f -a ! -newer a # and 조건
find . -name "*some_name*" -type f ! -newer a # 이것도 and 조건
find . -name "*some_name*" -o -type f -o ! -newer a # or 조건
tail
텍스트 파일의 끝 부분 내용을 확인하고자 할 때 주로 사용을 하시죠?
tail some_file
이건 많이들 아실텐데 표시할 라인수도 지정할 수 있구요.
tail -n 30 some_file # 파일 내 마지막 30라인 출력
파일 끝부분 내용을 출력한 후 프로그램이 끝나는 것이 아니라, 그 이후 추가된 파일 내용을 계속 출력할 수도 있습니다. 저는 서버 로그 등을 모니터링하면서 새로 추가된 내용을 계속 확인하고자 할 때 사용합니다. (물론 너무 많은 내용이 지나가면 보기 힘들긴 하지만요ㅎㅎ)
tail -f some_file
(명령어가 끝나지 않고 계속 출력. Ctrl+C를 통해 멈춤)
grep
파일 내에서 어떤 키워드를 검색할 때 주로 사용을 하시죠?
grep "some_keyword" some_file
단순히 몇 번 매칭이 되었는지 횟수를 세고 싶다면 이렇게 하구요
grep -c "some_keyword" some_file
검색된 키워드의 라인수를 표시할 수도 있고,
grep -n "some_keyword" some_file
어느 파일에서 찾았는지 알고 싶을 때는 파일명을 표시해 줄 수도 있습니다.
grep -H "some_keyword" *
현재 및 하위 디렉토리 내 모든 파일에서 검색도 할 수 있습니다.
grep -r "some_keyword" *
게다가 검색한 키워드의 위, 아래 n라인도 추가로 더 표시할 수 있습니다.
grep -A 2 -B 3 "some_keyword" * # 검색된 라인의 앞 3라인, 뒤 2라인 표시
특정 키워드를 찾는게 아니라, 반대로 제외하고 싶다면 아래와 같이 하시면 됩니다.
grep -v "exclude_keyword" *
아래 설명할 sed 명령어로 특정 라인을 제거하실수도 있지만 이 방법을 쓰기도 합니다.
grep -v "exclude_keyword" some_file > new_file
여기서 함정은… grep도 자주 사용은 하지만, 요즘에는 빠른 검색이 필요한 경우에는 ag (Silver Searcher)명령어를 더 자주 사용합니다ㅎㅎㅎ
sed
혹시 특정 파일에서 어떤 단어를 바꾸거나, 어떤 라인만 삭제를 하고 싶으시다구요? sed 명령어를 사용하시면 됩니다.
sed "s/from_str/to_str/g" file_name # from_str을 to_str로 치환
sed "/pattern/d" file_name # pattern이 포함된 라인 삭제
하지만 위와 같이 하시면 표준 출력 (stdout)으로 출력이 됩니다. 리다이렉션을 이용하여 다른 파일에 저장할 수 있구요.
sed "s/from_str/to_str/g" file_name > new_file1
sed "/pattern/d" file_name > new_file2
해당 파일을 바로 수정하실 수도 있습니다. 유용하기는 하지만, 원본 파일이 직접 수정이 되니 조심해서 사용을 하시고, 항상 백업(!)하시기 바랍니다ㅎㅎ
sed -i "s/from_str/to_str/g" file_name
sed -i "/pattern/d" file_name
사실 모든 옵션들을 다 설명하고자 하면 엄청난 분량이 될거구요. 제가 유용하게 쓰는 옵션들을 위주로 설명을 드렸습니다.
어떤 작업을 하고자하는지가 명확하다면, 이를 잘 정리해서 구글링만 잘 하는 것으로도 많은 문제를 푸실수 있으실 겁니다. 더불어 man 페이지와 -h 옵션도요ㅎㅎㅎ
마지막으로 짧게(?) 부연드릴 내용은…
파이프와 리다이렉션
위에서 설명드린 개개의 명령어들을 잘 사용하는 것도 도움이 되지만, 이것들을 엮어서 쓸 수 있는 파이프(|)와 리다이렉션(>, <)을 쓰시면 훨씬 더 많은 것들을 하실 수 있습니다.
파일 이름으로 검색을 한 후 그 파일들 내에서 검색을 한다던지…
find . -name "*some_files*" | xargs grep -n "keyword"
물론 find에 -exec 옵션을 써도 동일합니다만 파이프를 사용하는 방법도 있음을 보여드리는 것이구요. 가끔씩 쓰다보면 끝에 붙는 \;가 헷갈리기도 하고, find 뿐만 아니라 다른 곳에서도 같이 쓸 수 있는 xargs를 더 자주 씁니다. (개인적인 취향 입니다ㅎㅎㅎ)
이런식으로요…
ls *.txt | xargs grep -n "keyword" # 확장자가 txt인 파일 리스트에서 각각 grep을 수행.
위 예제들은 개별 인자들이 가장 마지막에 붙을 때이고, 혹시나 중간에 적을 필요하다면 이와 같이 하시면 됩니다.
ls *.txt | xargs -i cp {} target_dir
사실 위의 파이프를 이용한 예제는 좋은 예제는 아니며 굳이 저렇게 할 필요는 없습니다. 실무에서는 아래와 같이 하시면 됩니다ㅎㅎ
grep -n "keyword" *.txt
cp *.txt target_dir
많은 예시를 들어드리지는 못하였지만, 하고자 하는 작업을 잘 정리하고 개별작업과 이를 어떻게 연결시킬지를 생각해보신다면 많은 작업을 하실 수 있을거라 생각합니다.
제 글이 조금이나마 도움이 되어 리눅스 명령어와 쉘 스크립트로 더 많은 작업을 하실수 있기를 기대해봅니다. 알고 계신 유용한 팁들이 있다면 댓글 달아주시면 더 좋겠습니다 :-)
이 포스트는 GDG 서울에서 2021년 4월 14일에 주최한 글쓰기 공방 (모여서 각자 글쓰기, 모각글) 이벤트에 참가하여 작성한 글입니다.