arg를 통해 또는 파일이 존재하지 않는 경우 stdin에서 파일을 받는 다음 코드가 있습니다.
file=
column=
pattern=
path=
cmd="echo"
while getopts "f:c:e:" opt; do
case $opt in
f) file="$OPTARG";;
c) column="$OPTARG";;
e) pattern="$OPTARG";;
*) echo "Usage: $0 -f [file] -c [column] -e [pattern]"
esac
done
if [ -z "$file" ]; then
file=$(cat)
fi
이 접근 방식의 문제점은 cat이 파일이 아닌 파일에서는 작동하지 않는다는 것입니다. 예를 들어 stdout에서 가져온 경우:
cat data.csv | ./read.sh -c 2 -e " Max"
그러면 다음을 실행할 수 없습니다.
cat "$file"
Bash 스크립트에서는 대신 echo를 사용해야 합니다.
OTOH, 파일이라면 cat을 사용할 수 있고 모든 것이 괜찮습니다. 내 질문은 스크립트가 var $file이 실제 파일 이름인지 또는 stdout인지 인식하도록 만드는 방법입니다.
편집: 의견과 답변을 고려했으며 사용자가 지정하는 열과 정규식을 읽고 표준 입력이나 인수로 전달된 파일에서 고려할 수 있는 전체 스크립트를 사용자에게 제공하는 방법은 다음과 같습니다.
#!/bin/bash
unset -v column pattern filepath
cmd=echo
DELIMITER=","
while getopts "f:c:e:" opt; do
case $opt in
f) file="$OPTARG";;
c) column="$OPTARG";;
e) pattern="$OPTARG";;
*) printf>&2 '%s\n' "Usag: $0 [-f file] [-c column] [-e pattern]"; exit 1
esac
done
if [ -z "$file" ]; then
file=$(cat)
elif [ -z "$column" ]; then
echo "column number neeeded!"
elif [ -z "$pattern" ]; then
echo "pattern needed!"
fi
if [ -f "$file" ]; then
cmd="cat"
fi
if [ "$column" -eq 5 ]; then
DELIMITER=":"
fi
"$cmd" "$file" | awk -v col="$column" -v pattern="$pattern" -v del="$DELIMITER" -F "$DELIMITER" '{
for (i=1;i<=NF;i++) {
if ( i == col && $i == pattern ) {
print $0
} else if ( del == ":" && $i == pattern ) {
print $0
}
}
}'
exit 0
작동하지만 올바른 접근 방식이 아니라고 확신합니다. 내 파일에서 두 가지 작업을 모두 수행하도록 다시 시도했습니다.
cat data.csv | ./read.sh -c 2 -e "Max"
그리고:
./read.sh -f data.csv -c 2 -e "Max"
위의 스크립트는 작동하지만 최적화가 게임의 이름입니다!
답변1
의 경우 cat
표준 -
입력을 의미합니다. 많은 시스템에서 이 /dev/stdin
명령은 뿐만 아니라 모든 명령과 함께 작동 cat
하지만 Linux 또는 Cygwin에서는 /dev/stdin
stdin에서 열린 동일한 파일을 가리키며 어떤 경우에는 stdin과 정확히 동일하게 작동하지 않습니다.
그래서 당신은 이것을 할 수 있습니다 :
file=-
unset -v column pattern filepath
cmd=echo
while getopts f:c:e: opt; do
case $opt in
(f) file="$OPTARG";;
(c) column="$OPTARG";;
(e) pattern="$OPTARG";;
(*) printf>&2 '%s\n' "Usage: $0 [-f file] [-c column] [-e pattern]"; exit 1
esac
done
shift "$(( OPTIND - 1 ))"
cat -- "$file"
stdin()은 한 번만 읽을 수 있습니다 -
.
또한 참고하십시오:
- 오류는 stderr로 전송되어야 합니다.
echo
$0
임의의 데이터(예: 제어할 수 없는 데이터) 에는 사용할 수 없습니다 .[...]
동의한 대로 메시지를 사용하세요.임의로 선택할 수 있는, 따라서 의 경우 필수임을-f [file]
암시 하지만 해당 인수는 선택 사항이므로 여기서는 올바르지 않습니다.-f
path
스크립트가 결국 해석될 가능성이 있는 경우zsh
(sh
시뮬레이션이 아닌 경우)$path
배열 변수가 /$PATH
와 유사한 변수 이름을 지정하지 마십시오 .csh
tcsh
- 매개변수가 제공되었는지 확인하기 위해 null 테스트를 피해야 합니다. 예
-f ''
를 들어, 대신 초기화 시 을 사용하여 변수가 설정되지 않았는지 확인하고 나중에도 여전히 설정되지 않았는지 확인하세요. 또는 추가 부울 플래그 변수를 사용하여 옵션이 통과되었는지 여부를 기록합니다.$file
-f
unset -v var
[ -z "${var+set}" ]
-
사용자가 stdin이 아닌 현재 작업 디렉터리에서 호출 된 실제 파일을 의미하는 파일을 전달할 수 있도록 하려면 이를 핸들로 변환할 수 있습니다.-
./-
(f)
file=$(cat)
stdin에서 읽을 수 있는 내용을 읽고 이를file
변수(메모리 내)에 저장합니다. 따라서 다른 사람들이 말했듯이 변수 이름은 얻는 입력 파일의 내용이기 때문에 약간 오해의 소지가 있습니다. 하지만 그것은 또한으깨다당신이 얻는 것은$(...)
NUL 문자를 제거하거나 차단하는 zsh를 제외하고 모든 후행 개행 문자를 제거한 것입니다.echo
그것을 (임의의 데이터가 아닌) 사용한다면 스스로echo
피해를 입게 될 것입니다.
여기서는 반대 접근 방식을 취하고 -f
stdin에 인수로 전달된 파일을 열 수도 있습니다.
unset -v column pattern filepath
cmd=echo
while getopts f:c:e: opt; do
case $opt in
(f) exec < "$OPTARG";;
(c) column="$OPTARG";;
(e) pattern="$OPTARG";;
(*) printf>&2 '%s\n' "Usage: $0 [-f file] [-c column] [-e pattern]"; exit 1
esac
done
shift "$(( OPTIND - 1 ))"
cat
exec
파일을 열 수 없으면 POSIX 쉘이 자동으로 종료됩니다. -f
할당할 때와 같이 여러 옵션이 전달된 경우 $file
마지막 옵션만 고려됩니다.
답변2
실제 질문에 답하려면 test
. 그래서
if [ -z "$file" ] ; then
echo no file specified
elif [ -f "$file" ] ; then
echo given a valid file "$file"
else
echo Given "$file" but it is not a file
fi
그러나 나는 이것이 요점을 놓치고 있다고 생각합니다. file=$(cat)
당신은 변수 이름의 재사용에 대해 혼란스러워하고 있다고 생각합니다 file
. 그렇게 생각하면 file_contents=$(cat)
상황이 더 명확해질 것이라고 생각합니다.