我有以下代码,通过 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 是否是实际的文件名或标准输出。
编辑:我已经考虑了评论和答案,这是我如何向用户读取他们指定的列和正则表达式的整个脚本,并考虑它们从标准输入或作为参数传递的文件:
#!/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"
上面的脚本可以工作,但优化是游戏的名称!
要回答您的实际问题,您可以使用
test
查看它是否是一个文件。所以然而我认为这没有抓住要点,你已经
file=$(cat)
并且我认为你对变量名的重用感到困惑file
。如果你这么说file_contents=$(cat)
,我想你会发现事情更清楚。对于
cat
,-
表示标准输入。在许多系统上/dev/stdin
,可以使用任何命令,而不仅仅是cat
,而在 Linux 或 Cygwin 上,/dev/stdin
将指向与在 stdin 上打开的相同文件,在某些情况下与 stdin 的行为不完全相同。所以你可以这样做:
请注意,您只能读取 stdin (
-
) 一次。另请注意:
echo
不能用于任意数据(例如$0
您无法控制的数据)。[...]
按照惯例,在使用消息中意味着可选,因此对于-f [file]
,您暗示-f
是必需的,但它的参数是可选的,这在这里不正确。path
如果该脚本可能最终在zsh
(不在sh
仿真中时)被解释,请避免命名变量,其中$path
数组变量与/$PATH
类似。csh
tcsh
-f ''
您也会得到一个空值。相反,在初始化中使用以确保变量未设置,并检查以检查之后是否仍未设置。或者使用额外的布尔标志变量来记录选项是否通过。$file
-f
unset -v var
[ -z "${var+set}" ]
-
调用的实际文件,而不是 stdin,您可以将其转换为处理.-
./-
(f)
file=$(cat)
读取可以从 stdin 读取的内容并将其存储在file
变量中(在内存中)。正如其他人已经说过的那样,变量的名称有点误导,因为这是您得到的输入文件的内容。但它也是你得到的mangle内容,因为$(...)
删除了所有尾随换行符,除了 zsh 删除或阻塞了 NUL 字符。如果您echo
在其上使用(同样不能用于任意数据),echo
则会自行进行损坏。-f
在这里,您还可以采取相反的方法并打开作为参数传递给stdin 的文件:exec
请注意,当打开文件失败时,POSIX shell 将自动退出。如果传递了多个-f
选项,例如分配 时$file
,则仅考虑最后一个选项。