레이블이 bash인 게시물을 표시합니다. 모든 게시물 표시
레이블이 bash인 게시물을 표시합니다. 모든 게시물 표시

2025년 11월 24일 월요일

인공지능이 유발하는 과몰입과 과노동

아무리 고달프게 일을 해도 그 목적이 '취미'라면 노동이라고 하기는 곤란하다. 인공지능 덕분에 꿈도 꾸기 어려운 일을 업무와 취미 모든 측면에서 달성하고 있음은 분명한 사실이지만, 이것이 과몰입과 과노동을 유발한다. 조금만 더 하고 하루를 마치자는 유혹에서 벗어나기가 힘들기 때문이다. 오늘도 계산적 드럼 패턴학(computational drum patternology)의 발전을 위해서 노력하는 중이다.


이런 답변이 떡하니 나왔는데 이제 그만하고 침대로 가서 잠을 청할 기분이 나겠는가? 정성스럽게 만든 파이썬 코드를 이용하여 마이크로SD카드에 저장할 드럼 패턴 파일을 180개가 넘게 만들고, 그리드 시각화 자료까지 만들어 두었다. 관련 설명은 여기(ADP & ADT v2.2)에 있다.

아직 Nano Ardule Drum Pattern Player에는 몇 가지 작동이 불완전한 곳이 남아 있다. 드럼 패턴의 반복 재생을 시작할 때 이벤트가 약간 밀리고, LED와 박자가 맞지 않는 문제가 있었다. 완벽을 향해 다가가기 위해 아두이노 IDE, 즉 C++의 시간이 남았다.

챗GPT는 이런 유혹적인 메시지를 남겼다.

좋아요.
이제 확실하게 원인이 보입니다.
당신이 겪는 증상:

  • SGL 시작 시 첫 3스텝 늦게 소리가 나오고

  • LED는 1박자 늦게 켜지는 문제

이 두 가지는 하나의 원인에서 동시에 발생합니다.

휴식을 위하여 디버깅은 내일 할 일로 남겨 두도록 하자. 이번이 마지막이 아닐 수도 있으니 오늘은 더 이상 개미지옥에 빠지지 말자...라고 생각하였으나, 결국 유횩에 넘어가고 말았다. 다행스럽게도 너무 늦게까지 작업이 이어지지는 않았고, 가장 큰 문제는 해결하였다. 다른 사소한 문제가 발생하기도 하였으나.

이번 개발 작업을 전적으로 Windows에서 하면서 PowerShell을 많이 쓰게 되었다. 약간 생소하지만 객체지향 기반으로서 매우 합리적이라고 한다. 그러나 가장 큰 단점은 주변에 쓰는 사람이 없다는 것(출처: 파워셀을 쓰는 이유_클리앙)

# Bash
for f in *.mid; do
    python mid2adt.py "$f"
done
# PowerSHell
Get-ChildItem *.mid | ForEach-Object {
    python .\mid2adt.py $_.Name
}

화면으로 뿌려지는 명령어의 출력을 '>' 기호를 사용하여 간단하게 파일로 리다이렉션하려는 것조차 PowerShell에서는 다른 방법을 써야 한다. 차라리 WSL(Windows Subsystem for Linux)을 설치해서 bash를 쓰는 것이 나을까? 익숙함은 정말 강력한 무기가 되기 때문이다. 파일 시스템 경계와 언젠가 개발하게 될지도 모를 GUI application에만 주의하다면, WSL + bash가 더욱 나을 가능성이 있다. 챗GPT는 다음과 같이 깔끔하게 정리해 주었다.

작업 유형 더 좋은 선택
파이썬 개발, 스크립팅, 데이터 작업 WSL + Bash
윈도우 시스템 내 파일/폴더 정리 (특히 한글 포함) PowerShell
Git / conda 로 개발환경 구성 WSL
Windows 파일명/경로/권한 수정 PowerShell
Python 패키지 설치 충돌 예상 상황 WSL
한글 포함된 파일/폴더명 대량 변경 PowerShell

2019년 3월 13일 수요일

[Bash, shell] 구분자가 포함된 문자열의 조작 기법

예전에는 늘 Perl을 써서 작업하던 것을 shell 수준에서 구현하기 위해 노력하고 있다. 제목에서 밝힌 문자열은 사실은 파일의 제목을 의미한다. 오늘 글을 쓰는 목적은 NCBI에서 다운로드한 파일을 하나 가득 들어 놓고는 제목을 한꺼번에 변경하기 위한 방법을 정리하기 위함이다. 특정 균주(Paenibacillus polymyxa E681)에 대한 RefSeq assembly 다운로드 사이트(링크)를 방문해 보자.


파일의 이름은 '필드1_필드2_필드3_..' 형태이다. 여기서 구분자는 밑줄 문자(_, underscore)이다. 위치를 기준으로 하여 원하는 필드만 조합하여 파일명을 단순하게 바꾸는 사례를 알아보자. NCBI에서 유전체 정보를 일괄적으로 다운로드하여 이름을 바꾸는 방법은 나의 위키 페이지(링크)에 상세히 설명하였다. 여기에 나온대로 따라서 하면 다음과 같은 형태의 파일을 얻는다.

Rhodococcus_sp._H-CA8f_GCA_002501585.1.fna

때로는 빨갛게 표시한 부분만을 떼어서 파일명으로 삼고 싶을 때가 있다. iTOL 서버를 쓰는 경우에는 단순하게 표시된 자료로 만든 newick tree file을 업로드한 다음 실제로 표시할 label을 별도로 제공하는 것이 더 합리적이다.

그렇다면 위에서 보인 파일명을 구분자(_)로 나눈 뒤 5, 6번째 필드를 붙인 것으로 바꾸면 된다. 이때 유용한 명령어는 cut이다.

$ ls *fna | while read F
> do
> mv $F $(cut -d'_' -f5,6 <<<$F)
> done

꺾쇠 세 개가 연달아 표시된 줄이 약간 난해한데, 어쨌든 잘 작동은 한다. 그러나 이 방법은 필드의 수가 엄격하게 고정된 경우에 한하여 쓸 수 있다. 파일명의 세번째 필드, 그러니까 strain 명에 해당하는 곳에 또 밑줄이 들어간 경우가 종종 있다. 'ATCC 842'와 같이 원래는 공백이지만 파일명에 공백을 넣는 것이 별로 바람직하지 않기 때문에 밑줄을 추가적으로 넣게 된 것이다. 이러한 상황에서는 '구분자를 떼어낸 다음 몇 번째 필드를 취하라' 하는 식으로는 원하는 결과를 얻기 어렵다. 차라리 '앞에서 처음, 혹은 뒤에서 처음'하는 방법이 더 낫다. 이때 BASH의 문자열 조작 기법이 매우 유용하게 떠오른다.

상세하게 공부를 하려면 Advanced Bash-Scripting Guide의 제10장 Manipulating Variables를 숙독하라. 나는 여기에서 꼭 필요한 부분만을 골라서 설명하겠다. 다음의 예제만 잘 보면 뭐가 어떻게 돌아가는지를 잘 알 수 있다. #와 %는 앞 또는 뒤로부터 시작하는 매치를 삭제하는 것이다. *를 쓰지 않고 ${NAME#_}라고만 쓰면 앞부분부터 시작해서 첫번째 '_'가 나오는 곳까지를 삭제할 것만 강렬한 욕구가 느껴지지만 이건 오해다(사실 이것 때문에 혼동을 많이 했다). 반드시 *_라고 써야 하고, #를 사용하는 경우에는 _*라고 해야 한다. #와 ##, %와 %%의 차이는 shortest(하나) or longest match(둘)를 의미하는 것이다.

$  NAME=abc_def_123_456.txt
$ echo ${NAME#*_}
def_123_456.txt
$ echo ${NAME##*_}
456.txt
$ echo ${NAME%_*}
abc_def_123
$ echo ${NAME%%_*}
abc
$ echo ${NAME/_/XYZ}
abcXYZdef_123_456.txt
$ echo ${NAME/_*/}
abc
$ echo ${NAME/*_/}
456.txt

그러면 파일명을 구성하는 필드의 수가 일정하지 않다 하더라도 맨 뒷부분을 이용하여 assembly accession만을 떼어내는 것이 가능하다.

$ ls *fna | while read F
> do
> mv $F GCA_${F##*_}
> done

변수 F의 앞에서부터 시작하여 *_를 longest match로 삭제하면 ...GCA_의 나머지 부분이 남는다. 이렇게 얻은 값의 앞에 다시 GCA_를 붙이면 된다. 혹은 while-do 블록 내의 명령어를 mv $F GCA_${F#*_GCA_}으로 써도 결과는 같다. _GCA_는 변수 F의 값에서 단 한번만 존재하므로(철저한 사람이라면 균주명에 앞뒤에 공백을 포함하는 GCA라는 이름이 들어있지는 않은지 확인을 해 보겠지만) #를 한 번만 써도 된다.

대충 써 왔던 기법이 이제 좀 정리가 되었다.

2019년 2월 13일 수요일

[BASH] cut 명령을 이용하여 파일 이름을 간략하게 정리하기

cut - remove sections from each line of files (print selected parts of lines from each file to standard out)

커맨드 라인에서 man cut이라고 치면 나오는 설명이다. CSV 파일처럼 각 라인이 일정한 구분자(delimiter)로 나뉜 'section'의 집합으로 이루어진 경우, 이를 나누어서 작업하는 데에 아주 적당한 명령이다. 구분자를 제공하지 않으면 라인 내의 위치를 기준으로 잘라내는 것도 가능하다.

cut을 사용하면 NCBI에서 다운로드한 유전체 정보 파일의 이름을 간략히 하는 일이 매우 쉬워진다. RefSeq에서 받은 FASTA 파일의 이름은 다음과 같이 여러 필드가 밑줄('_')로 구분된 형태를 하고 있다.
GCF_000152245.2_ASM15224v2_genomic.fna
GCF_000242675.1_Euba_infi_F0142_V1_genomic.fna
GCF_900100105.1_IMG-taxon_2593339210_annotated_assembly_genomic.fna
굵은 글씨로 표현된 assembly accession 뒤의 정보는 assembly ID로서 제출자가 정하는 것이라서 특별히 정해진 규약이 없다. 그래서 rename 명령어나 $VAR{//문자열} 방법으로 처리하기에 좋지 않다. cut을 사용하면 밑줄을 delimiter로 삼아서 첫번째 및 두번째 섹션을 취한 뒤, 여기에 .fna 확장자를 붙이는 것으로 새 파일의 이름을 정하면 된다. cut을 사용하면 이러한 작업을 매우 간단하게 할 수 있다.


$ ls | while read f
> do
> cp $f $(echo $f | cut -d'_' -f 1,2).fna
> done

더 이상의 무슨 설명이 필요한가? 더욱 많은 사례는 Linux Cut Command With Samples를 방문해 보라.

cut 명령어의 사례를 보면 -f1,2 -f3과 같이 옵션과 지정한 값 사이에 아무런 공백을 넣지 않는 것을 보게 된다. 옵션을 길게 쓰려면 --fields=LIST와 같이 등호('=') 좌우로 공백을 넣지 않는 것이 맞다. 그러나 짧게 쓰는 경우라면 -f 1처럼 사이에 공백을 넣는 것이 자연스럽지 않을까? 실제로 작동을 시켜 보면 -f1과 -f 1 어느 것으로 하든 상관은 전혀 없다. 어쩌면 이러한 관행은 옵션을 인수(여기에서는 작업 대상 파일명)와 명확히 구분하기 위함인지도 모른다. 옵션과 인수(argument)는 다름에 유의해아 한다. 옵션은 명령의 실제 동작을 세부적으로 조절하는 것이고, 인수는 작업이 이루어지는 대상이다.