아래의 for 루프를 이해하고 단순화하고 싶습니다. 예를 들어 디렉터리의 각 예제에 대한 rem 파일을 연결하고 싶습니다.
문서:
file1.1.fq
file1.rem.1.fq
file1.2.fq
file1.rem.2.fq
file2.1.fq
file2.rem.1.fq
file2.2.fq
file2.rem.2.fq
for 루프:
list=`for i in *rem*.1.fq; do echo $i | cut -f 1 -d \.; done`
for i in $list; do cat $i.rem.1.fq $i.rem.2.fq > $i.rem.b.fq; done
목록을 작성하지 않고도 이 작업을 수행할 수 있나요? 기능은 무엇입니까 cut -f 1 -d
? 파일 이름의 일부가 목록의 두 부분 사이에 있으면 cat $i.rem.1.fq
작동하지만 작동하지 않는 이유는 무엇입니까? 이는 이전의 모든 항목(예: file1)을 캡처한다는 의미입니까?cat $i.1.fq
rem
*
*rem*
답변1
노력하다:
for i in *.rem.1.fq; do
cat -- "$i" "${i%.1.fq}.2.fq" > "${i%.1.fq}.b.fq"
done
파일 존재 여부 확인을 추가할 수도 있습니다.
for i in *.rem.1.fq; do
if [ -e "${i%.1.fq}.2.fq" ] && [ ! -e "${i%.1.fq}.b.fq" ]; then
cat -- "$i" "${i%.1.fq}.2.fq" > "${i%.1.fq}.b.fq"
fi
done
질문에서 제안된 접근 방식은 오류가 발생하기 쉽습니다. for
파일에 공백이 포함되어 있으면 두 번째 루프가 제대로 작동하지 않을 수 있습니다.
cut -f 1 -d.
문자열을 필드(이 경우 로 구분 .
)로 분할하고 요청된 필드(이 경우 첫 번째 필드만)를 출력합니다. 문자열이 주어지면 file 1.whatever
출력됩니다 file 1
. 다시 말하지만, glob 패턴이 – 와일드카드 일치로 파일 이름을 *rem*.1.fq
반환할 수 있다는 점을 고려하면 오류가 발생하기 쉽습니다.anyremthing.1.fq
*
아무것(포함하다아무것도 없다).
더 나은 옵션은 단일 루프를 수행하고 인수 확장을 사용하는 것입니다. 루프 내에서 대체 형식을 사용하여 관련 이름을 가진 다른 파일과 일치시킵니다.
- 위에서는 glob 패턴이 사용되었습니다
*.rem.1.fq
. 더 범위를 좁힐 수도 있습니다.file[0-9].rem.1.fq
. ${param%string}
루프에서 접미사를 제거하는 데 사용됩니다.1.fq
. 많은 쉘은 다른 형태의 매개변수 확장 대체도 지원합니다.${param/string/repl}
.
"$param"
또한 일반적으로 모두 인용 하거나 바꾸는 것이 좋습니다 . 그렇지 않으면 대부분의 쉘이 필드 분할 및 파일 이름 생성을 적용하므로 대신 "$(command)"
시도하게 될 수도 있습니다 .cat file 1
cat 'file 1'
--
파일 이름 이 -
.