我被这个问题困住了: 我编写了一个shell脚本,它从stdin获取了一个包含许多行的大文件,这就是它的执行方式:
./script < filename
我想使用该文件作为脚本中另一个操作的输入,但我不知道如何将该文件的名称存储在变量中。
它是一个脚本,它从stdin获取一个文件作为参数,然后在它自己的文件中执行awk操作。如果我用脚本写的话说:
script:
#!/bin/sh
...
read file
...
awk '...' < "$file"
...
它只读取输入文件的第一行。 我找到了这样写的方法:
Min=-1
while read line; do
n=$(echo $line | awk -F$delim '{print NF}')
if [ $Min -eq -1 ] || [ $n -lt $Min ];then
Min=$n
fi
done
等待处理需要很长时间,似乎awk需要很长时间。 那么如何改进呢?
答案 0 :(得分:2)
你过度了。您调用脚本的方式:
但是awk
默认情况下已经从stdin获取输入,所以你需要做的就是:
awk
任何文件名参数,它将自动成为包装shell的标准输入awk
部分之前不消耗任何输入。具体来说:没有read
如果您的脚本完全存在,那么它会缩减到awk
调用,因此您可以考虑完全取消它,直接调用awk
。或者直接将您的脚本设为awk
而不是sh
。
除此之外:您的while read line
/多个awk
变体(问题中的变体)速度慢的原因是因为它为输入的每一行产生awk
进程,和处理产生的处理速度比处理单行的awk
慢。生成tmpfile / single awk
变体(你的答案中的变体)仍然有点慢的原因是因为它逐行生成tmpfile,每次都重新打开以附加。
答案 1 :(得分:2)
/dev/stdin
在这里非常有用。
事实上,它只是一系列指向您输入的链接。
因此,编写cat /dev/stdin
将为您提供文件中的所有输入,您可以拒绝使用输入文件名。
现在回答问题:)递归阅读链接,从/dev/stdin
开始,你会得到文件名。 Bash代码:
r(){
l=`readlink $1`
if [ $? -ne 0 ]
then
echo $1
else
r $l
fi
}
filename=`r /dev/stdin`
echo $filename
UPD:
在Ubuntu中,我找到了一个选项-f
来读取链接。即readlink -f /dev/stdin
给出相同的输出。某些系统可能缺少此选项。
UPD2:测试(test.sh是上面的代码):
$ ./test.sh <input # that is a file
/home/sfedorov/input
$ ./test.sh <<EOF
> line
> EOF
/tmp/sh-thd-214216298213
$ echo 1 | ./test.sh
pipe:[91219]
$ readlink -f /dev/stdin < input
/home/sfedorov/input
$ readlink -f /dev/stdin << EOF
> line
> EOF
/tmp/sh-thd-3423766239895 (deleted)
$ echo 1 | readlink -f /dev/stdin
/proc/18489/fd/pipe:[92382]
答案 2 :(得分:0)
将脚本修改为将输入文件名作为参数,然后从脚本中的文件中读取:
$ ./script filename
在script
:
filename=$1
awk '...' < "$filename"
如果您的脚本只是从标准输入读取,则无法保证是提供输入的命名文件;它可以很容易地从管道或网络插座中读取。
答案 3 :(得分:0)
如何以不同方式调用脚本将YourFilename的标准输出管道输入 你的scriptName如下(cat文件名的标准输出现在变成标准 输入到您的脚本,实际上在这种情况下是awk命令 因为我有文件名Names.data和脚本showNames.sh执行如下
cat Names.data | ./showNames.sh
文件名Names.data的内容 哈克贝利·芬恩 杰克斯普拉特 Humpty Dumpty
scrip的内容; t showNames.sh
#!/bin/bash
#whatever awk commands you need
awk "{ print }"
答案 4 :(得分:-2)
好吧,我终于找到了解决问题的方法,虽然这需要几秒钟。
grep '.*' >> /tmp/tmpfile
Min=$(awk -F$delim 'NF < min || min == "" { min = NF };END {printmin}'</tmp/tmpfile)
只需将每一行附加到一个临时文件中,以便在从stdin读取后,tmpfile与输入文件相同。