下面的Perl脚本(my.pl)既可以从命令行参数中的文件读取,也可以从标准输入(STDIN)读取:

while (<>) {
   print($_);
}

Perl my.pl将从标准输入中读取,而Perl my.pl .txt将从a.txt中读取。这很方便。

Bash中也有类似的功能吗?


当前回答

作为一种变通方法,你可以使用/dev目录下的stdin设备:

....| for item in `cat /dev/stdin` ; do echo $item ;done

其他回答

下面的解决方案从文件读取(如果脚本调用时将文件名作为第一个参数$1),否则从标准输入读取。

while read line
do
  echo "$line"
done < "${1:-/dev/stdin}"

替换${1:-…}如果定义了,则接受$1。否则,使用自己进程的标准输入的文件名。

每当IFS中断输入流时,回显解决方案就添加新行。@fgm的回答可以稍微修改一下:

cat "${1:-/dev/stdin}" > "${2:-/dev/stdout}"
#!/usr/bin/bash

if [ -p /dev/stdin ]; then
       #for FILE in "$@" /dev/stdin
    for FILE in /dev/stdin
    do
        while IFS= read -r LINE
        do
            echo "$@" "$LINE"   #print line argument and stdin
        done < "$FILE"
    done
else
    printf "[ -p /dev/stdin ] is false\n"
     #dosomething
fi

运行:

echo var var2 | bash std.sh

结果:

var var2

运行:

bash std.sh < <(cat /etc/passwd)

结果:

root:x:0:0::/root:/usr/bin/bash
bin:x:1:1::/:/usr/bin/nologin
daemon:x:2:2::/:/usr/bin/nologin
mail:x:8:12::/var/spool/mail:/usr/bin/nologin

我将上述所有答案结合起来,创建了一个适合我需要的shell函数。这是我的两台Windows 10机器的Cygwin终端,我在它们之间有一个共享文件夹。我需要能够处理以下问题:

Cat文件。cpp | tx Tx < file.cpp tx file.cpp

如果指定了特定的文件名,则在复制过程中需要使用相同的文件名。在输入数据流通过管道的地方,我需要生成一个包含小时、分钟和秒的临时文件名。共享的主文件夹包含以星期为单位的子文件夹。这是为了组织的目的。

看,我需要的终极剧本

tx ()
{
  if [ $# -eq 0 ]; then
    local TMP=/tmp/tx.$(date +'%H%M%S')
    while IFS= read -r line; do
        echo "$line"
    done < /dev/stdin > $TMP
    cp $TMP //$OTHER/stargate/$(date +'%a')/
    rm -f $TMP
  else
    [ -r $1 ] && cp $1 //$OTHER/stargate/$(date +'%a')/ || echo "cannot read file"
  fi
}

如果有任何方法,你可以看到进一步优化这一点,我想知道。

更准确的说……

while IFS= read -r line ; do
    printf "%s\n" "$line"
done < file