meta.txt
다음 정보가 포함된 텍스트 파일이 있습니다.
이라는 또 다른 것이 있습니다.data
output_folder = "data"
conv
아래와 같이 함수 내부에 이름이 지정된 함수를 실행하려면 of에서 경로 조회를 사용하여 system
파일을 다음으로 변환합니다.fastq.gz
2nd column
meta.txt
fastq.gz
fastq.txt
tail -n+2 meta.txt | awk -v output_folder=${output_folder} '{ system("convert " $2 $output_folder/"fastq.txt") }'
하지만 결국 다음과 같은 오류가 발생했습니다.
awk: cmd. line:1: (FILENAME=- FNR=1) fatal: division by zero attempted
답변1
awk는 다른 도구를 순서대로 호출하는 도구가 아니라 텍스트를 조작하기 위한 도구입니다. 이것이 쉘의 목적입니다. 테스트할 텍스트 입력/출력을 제공하지 않았으므로 이는 테스트되지 않은 추측이지만 코드에서 수행하려는 작업은 다음 셸 루프뿐입니다( IFS
설정 또는 수정되지 않았다고 가정).
while read -r _ file; do
convert "$file" "$output_folder/fastq.txt"
done < <(tail -n +2 meta.txt)
어떤 이유로 호출에 awk를 사용하고 싶다면 convert
다음과 같이 하세요.
output_folder="$output_folder" \
awk '
BEGIN { outfold = ENVIRON["output_folder"] }
NR>1{ system("convert \047" $2 ("\047 \047" outfold "/fastq.txt\047") }
' meta.txt
그러나 이는 system()이 호출될 때마다 하위 쉘을 생성하므로 awk를 사용하여 이점을 얻기에는 너무 느립니다.
바라보다awk 스크립트에서 쉘 변수를 사용하는 방법ENVIRON[]
awk 변형 이 ENVIRON[]
.
0으로 나누기 오류가 발생하는 이유는 내부 코드는 다음과 같습니다 system()
.
"convert " $2 $output_folder/"fastq.txt"
숫자가 아닌 문자열이 포함될 output_folder
수 있으므로 실행하면 gawk --lint
다음과 같은 경고 메시지가 표시됩니다.
warning: attempt to field reference from non-numeric value
/
그것에 대해, 그러나 리터럴 문자열이 뒤에 오는 나누기 연산자가 있습니다 "fastq.txt"
. 이 문자열이 숫자로 처리되면(이 예에서와 같이) 0과 동일하므로 "0으로 나누기"입니다.
귀하의 의견과 업데이트된 질문에 관해:
질문에서 이 기능을 변경하세요.
function convert {
INPUT=$1
OUTPUT=$2
INPUT_R=0
if [ "${INPUT: -3}" == ".gz" ]; then
INPUT_S=1
fi
if [[ $INPUT_R -eq 1 ]]; then
gunzip -c ${INPUT} > ${OUTPUT}
else
cp -v ${INPUT} ${OUTPUT}
fi
chmod ug+rw ${OUTPUT}
}
문제를 해결합니다(일부는http://shellcheck.net당신에게 말할 것입니다 - 쉘에 더 익숙해질 때까지 항상 스크립트에서 이것을 실행하십시오):
#!/usr/bin/env bash
convert() {
local input=$1 output=$2
if [[ $input = *.gz ]]; then
gunzip -c -- "$input" > "$output"
else
cp -v -- "$input" "$output"
fi &&
chmod -- ug+rw "$output"
}
output_folder='/Users/doc'
# now include this:
while read -r _ file; do
convert "$file" "$output_folder/fastq.txt"
done < <(tail -n +2 meta.txt)
# or this at the end of the same script:
export -f convert # only works if sh is bash in your env since
# system() will call sh to run the command
output_folder="$output_folder" \
awk '
BEGIN { outfold = ENVIRON["output_folder"] }
NR>1{ system("convert \047" $2 ("\047 \047" outfold "/fastq.txt\047") }
' meta.txt
awk가 서브셸에서 함수를 호출할 수 있도록 하려면 함수를 내보내야 합니다. 사용하려는 출력 파일이 쓰기 가능하지 않은 이유를 스스로 파악해야 하지만 쉬울 것입니다.
~처럼스티븐 차제라스의견에 언급된 바와 같이(현재 구현된 위의 다른 의견에 감사드립니다):
- 파일 경로에 문자가 포함되지 않는다는 보장이 없으면
'
임의 명령 주입 취약점과 동일합니다. - 이는
\47
ASCII 기반 시스템을 가정합니다(현재로서는 상대적으로 안전한 가정). chmod ug+rw
이를 0으로 변경하면 이를 방지할 수 있습니다umask
(그러나 월드 파일을 쓰기 가능으로 만드는 것은 어쨌든 매우 나쁜 생각처럼 들립니다).
답변2
치명적: 0으로 나누려고 시도함
예, 인용 문제가 있으므로 슬래시는 /
원하는 방식으로 문자열 작업에 포함되지 않습니다.
이는 말도 안되는 인용을 포함하여 파이프라인 디버깅을 위한 매우 일반적인 전략입니다 awk
.
문자열을 생성한 다음 cmd
실행 system(cmd)
하고 최선을 다하는 대신 다른 접근 방식을 취하십시오. awk 스크립트에 물어보세요산출명령 문자열은 표준 출력으로 전송되고 파이프의 마지막 부분은 sh
(또는 bash
)입니다.
이것의 장점은
- 에서 제안된 명령을 보고 시작할 수 있습니다
awk
.그 다음에일단 상황이 좋아 보이| sh
거나 ,| sh -x
상황이 좋아 보이면 - 잠재적으로 유해한 명령(예:)을 디버깅하는 동안
rm
먼저바라보다당신 앞에 무엇이 오나요?달리기그 명령.
답변3
다음이 필요한 것 같습니다.
(
umask 0
unset -v IFS
read -r discarded_header &&
IFS=' ' read -r discarded_first_field file &&
gzip -dcf < "$file" > data/fasq.txt
) < meta.txt
누구나 읽고 쓸 수 있는 파일 사본(아마도 압축되지 않음)을 만드는 것이 요점이라면 파일 경로는 meta.txt
.