代码之家  ›  专栏  ›  技术社区  ›  mickp

为什么在这里使用doc时,不存在/“不存在”?[副本]

  •  3
  • mickp  · 技术社区  · 6 年前

    我想要一个Bash脚本,它可以从文件或stdin获取输入,就像 grep ,例如

    $ cat hw.txt
    Hello world
    
    $ grep wor hw.txt
    Hello world
    
    $ echo 'Hello world' | grep wor
    Hello world
    
    $ grep wor <<< 'Hello world'
    Hello world
    

    一切都很好。但是使用以下脚本

    read b < "${1-/dev/stdin}"
    echo $b
    

    如果使用herestring则失败

    $ hw.sh hw.txt
    Hello world
    
    $ echo 'Hello world' | hw.sh
    Hello world
    
    $ hw.sh <<< 'Hello world'
    /opt/a/hw.sh: line 1: /dev/stdin: No such file or directory
    
    0 回复  |  直到 11 年前
        1
  •  10
  •   Austin Phillips    11 年前

    使用 /dev/stdin 以这种方式可能会有问题,因为您正试图使用文件系统中的名称获取stdin的句柄( /开发/标准 )而不是使用bash已经作为stdin(文件描述符0)提供给您的文件描述符。

    这里有一个小脚本供您测试:

    #!/bin/bash
    
    echo "INFO: Listing of /dev"
    ls -al /dev/stdin
    
    echo "INFO: Listing of /proc/self/fd"
    ls -al /proc/self/fd
    
    echo "INFO: Contents of /tmp/sh-thd*"
    cat /tmp/sh-thd*
    
    read b < "${1-/dev/stdin}"
    echo "b: $b"
    

    在我的cygwin安装中,这会产生以下结果:

    ./s <<< 'Hello world'
    
    
    $ ./s <<< 'Hello world'
    INFO: Listing of /dev
    lrwxrwxrwx 1 austin None 15 Jan 23  2012 /dev/stdin -> /proc/self/fd/0
    INFO: Listing of /proc/self/fd
    total 0
    dr-xr-xr-x 2 austin None 0 Mar 11 14:27 .
    dr-xr-xr-x 3 austin None 0 Mar 11 14:27 ..
    lrwxrwxrwx 1 austin None 0 Mar 11 14:27 0 -> /tmp/sh-thd-1362969584
    lrwxrwxrwx 1 austin None 0 Mar 11 14:27 1 -> /dev/tty0
    lrwxrwxrwx 1 austin None 0 Mar 11 14:27 2 -> /dev/tty0
    lrwxrwxrwx 1 austin None 0 Mar 11 14:27 3 -> /proc/5736/fd
    INFO: Contents of /tmp/sh-thd*
    cat: /tmp/sh-thd*: No such file or directory
    ./s: line 12: /dev/stdin: No such file or directory
    b: 
    

    这个输出显示bash正在创建一个临时文件来保存您的HERE文档( /tmp/sh-thd-1362969584 )并使其在文件描述符0 stdin上可用。但是,临时文件已与文件系统解除链接,因此无法通过文件系统名(如 /开发/标准 . 可以通过读取文件描述符0来获取内容,但不能通过尝试打开 /开发/标准 .

    在Linux上 ./s 上面的脚本提供了以下内容,显示文件已解除链接:

    INFO: Listing of /dev
    lrwxrwxrwx 1 root root 15 Mar 11 09:26 /dev/stdin -> /proc/self/fd/0
    INFO: Listing of /proc/self/fd
    total 0
    dr-x------ 2 austin austin  0 Mar 11 14:30 .
    dr-xr-xr-x 7 austin austin  0 Mar 11 14:30 ..
    lr-x------ 1 austin austin 64 Mar 11 14:30 0 -> /tmp/sh-thd-1362965400 (deleted) <---- /dev/stdin not found
    lrwx------ 1 austin austin 64 Mar 11 14:30 1 -> /dev/pts/12
    lrwx------ 1 austin austin 64 Mar 11 14:30 2 -> /dev/pts/12
    lr-x------ 1 austin austin 64 Mar 11 14:30 3 -> /proc/10659/fd
    INFO: Contents of /tmp/sh-thd*
    cat: /tmp/sh-thd*: No such file or directory
    b: Hello world
    

    更改脚本以使用提供的stdin,而不是尝试通过 /开发/标准 .

    if [ -n "$1" ]; then
        read b < "$1"
    else
        read b
    fi
    
        2
  •  1
  •   Community Mic    7 年前

    bash 分析一些文件名(如 /dev/stdin )特别是,这样即使它们不在文件系统中,也能被识别。如果你的剧本没有 #!/bin/bash 在上面,和 /开发/标准 不在您的文件系统中,您的脚本可能使用 /bin/sh ,这是意料之中的 /开发/标准 成为一个文件。

    (这也许不是一个答案,而是对 Austin's answer .)

        3
  •  0
  •   zzk    11 年前
    $ cat ts.sh 
    read b < "${1-/dev/stdin}"
    echo $b
    
    $ ./ts.sh <<< 'hello world'
    hello world
    

    我没问题。我在Mac OS X上使用bash 4.2.42。

        4
  •  -1
  •   djoot    11 年前

    你在这里输入错了

    read b < "${1-/dev/stdin}"
    

    尝试

    read b < "${1:-/dev/stdin}"