AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 440554
Accepted
C0deDaedalus
C0deDaedalus
Asked: 2018-04-29 01:50:44 +0800 CST2018-04-29 01:50:44 +0800 CST 2018-04-29 01:50:44 +0800 CST

为什么 shell 将 $(<file) 的部分输出视为命令?

  • 772

我在阅读IFS 上的博客时看到了这一行:

for i in $(<test.txt)

并认为$(<test.txt)将文件内容打印到 STDOUT。我可能在这方面错了,但出于好奇,我试图在 shell 上做到这一点。所以拿起一个名为array具有随机数据的随机文件和

首先做了一个cat array给我的:

amit@C0deDaedalus:~/test$ 
amit@C0deDaedalus:~/test$ cat array
1)      Ottawa  Canada          345644
2)      Kabul   Afghanistan     667345
3)      Paris   France          214423
4)      Moscow  Russia          128793
5)      Delhi   India           142894

然后这样做$(<array)给了我这个:

amit@C0deDaedalus:~/test$ $(<array)
1)      Ottawa  Ca: command not found

我只知道它<用于输入重定向,但没有得到 shell 在这里解释为命令的确切内容。

任何人都可以在 shell 中解释这个奇怪的输出背后的概念吗?

更新 :-

在运行set -x时它给出了这个:

amit@C0deDaedalus:~/test$ $(<array)
+ '1)' Ottawa Canada 345644 '2)' Kabul Afghanistan 667345 '3)' Paris France 214423 '4)' Moscow Russia 128793 '5)' Delhi India 142894
+ '[' -x /usr/lib/command-not-found ']'
+ /usr/lib/command-not-found -- '1)'
1): command not found
+ return 127
amit@C0deDaedalus:~/test$ 
shell output
  • 1 1 个回答
  • 393 Views

1 个回答

  • Voted
  1. Best Answer
    nxnev
    2018-04-29T02:24:18+08:002018-04-29T02:24:18+08:00

    该$(command)语法command在子 shell 环境中执行,并将其自身替换为command. 而且,正如 Bash Manual 所说,$(< file)它只是一个更快的等价物$(cat file)(不过,这不是 POSIX 功能)。

    因此,当您运行 时$(<array),Bash 会执行该替换,然后它将第一个字段用作命令的名称,将其余字段用作命令的参数:

    $ $(<array)
    1): command not found
    

    我没有任何1)命令/功能,因此它会打印一条错误消息。

    但是在您的特定情况下,您可能会收到不同的错误消息,因为您修改了 IFS 变量:

    $ IFS=n; $(<array)
    1)      Ottawa  Ca: command not found
    

    编辑 1

    我的猜测是你IFS被某种方式修改了,所以这就是为什么你的 shell 试图执行1) Ottawa Ca而不是1). 毕竟,您正在阅读与IFS相关的文章。IFS如果您最终得到一个奇怪的值,我不会感到惊讶。

    该IFS变量控制所谓的单词拆分或字段拆分。它基本上定义了 shell 如何在扩展上下文中解析数据(或其他命令,如read)。

    Bash 手册解释了这个主题:

    3.5.7 分词

    shell 会扫描双引号内未出现的参数扩展、命令替换和算术扩展的结果以进行分词。

    shell 将每个字符$IFS视为分隔符,并将其他扩展的结果拆分为使用这些字符作为字段终止符的单词。如果IFS未设置,或者它的值恰好<space><tab><newline>是默认值,则忽略先前扩展结果的开头和结尾处的 、 和 序列,并且任何不在开头或结尾的字符序列都<space>用于<tab>分隔单词。如果具有除默认值以外的值,则在单词的开头和结尾处忽略空格字符、和的序列,只要空格字符在(一个空格字符) 的值中。里面的任何角色都不是<newline>IFSIFSspacetabnewlineIFSIFSIFSIFS空白与任何相邻IFS的空白字符一起分隔一个字段。一系列IFS空白字符也被视为分隔符。如果 的值为IFS空,则不发生分词。

    显式空参数 (""或'') 被保留并作为空字符串传递给命令。不带引号的隐式空参数由没有值的参数的扩展产生,被删除。如果在双引号中扩展了没有值的参数,则会产生空参数并保留并作为空字符串传递给命令。当引用的空参数作为扩展为非空的单词的一部分出现时,将删除空参数。即,词在分词和空参数去除后-d''变为。-d

    请注意,如果没有发生扩展,则不执行拆分。

    以下是一些关于IFS命令替换用法的示例:

    示例 1:

    $ IFS=$' \t\n'; var='hello     world'; printf '[%s]\n' ${var}
    [hello]
    [world]
    
    $ IFS=$' \t\n'; var='hello     world'; printf '[%s]\n' "${var}"
    [hello     world]
    

    在这两种情况下,IFSis <space><tab><newline>(默认值)、varishello world和 there'sprintf语句。但请注意,在第一种情况下会执行分词,而在第二种情况下则不会(因为双引号会抑制这种行为)。分词发生在未引用的扩展中。

    示例 2:

    $ IFS='x'; var='fooxbar'; printf '[%s]\n' ${var}
    [foo]
    [bar]
    
    $ IFS='2'; (exit 123); printf '[%s]\n' ${?}
    [1]
    [3]
    

    既不${var}也不${?}包含任何空白字符,因此人们可能认为在这种情况下分词不会成为问题。但这不是真的,因为IFS可能会被滥用。IFS几乎可以持有任何价值,而且很容易被滥用。

    示例 3:

    $ $(echo uname)
    Linux
    
    $ $(xxd -p -r <<< 64617465202d75)
    Sat Apr 28 12:46:49 UTC 2018
    
    $ var='echo foo; echo bar'; eval "$(echo "${var}")"
    foo
    bar
    

    这与分词无关,但请注意我们如何使用一些肮脏的技巧来注入代码。

    相关问题:

    • 为什么我的 shell 脚本会因空格或其他特殊字符而窒息?
    • 忘记在 bash/POSIX shell 中引用变量的安全隐患
    • 17

相关问题

  • 这个命令是如何工作的?mkfifo /tmp/f; 猫/tmp/f | /bin/sh -i 2>&1 | 数控 -l 1234 > /tmp/f

  • FreeBSD 的 sh:列出函数

  • 有没有办法让 ls 只显示某些目录的隐藏文件?

  • grep -v grep 有什么作用

  • 如何将带有〜的路径保存到变量中?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve