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 / 问题 / 408620
Accepted
antonio
antonio
Asked: 2017-12-04 14:23:57 +0800 CST2017-12-04 14:23:57 +0800 CST 2017-12-04 14:23:57 +0800 CST

位置参数中的分词

  • 772

考虑以下示例:

IFS=:
x="a   :b"   # three spaces
echo ["$x"]  # no word splitting
# [a   :b]   # as is
echo [$x]    # word splitting 
# [a    b]   # four spaces

分词识别单词"a "(三个空格)和"b",用冒号分隔,然后echo用中间的空格连接单词。
但是,当使用 的值$x作为函数参数时,我发现很难解释结果。

args(){ echo ["$*"];}
args a   :b  # three spaces
# [a::b]

和:

args(){ echo [$*];}
args a   :b  # three spaces
# [a  b]     # two spaces

$*扩展为所有位置参数组合的值。此外,"$*"等价于"$1c$2",其中c是 IFS 变量值的第一个字符。

args(){ echo ["$1"]["$2"]; }
args a   :b  # three spaces
# [a][:b]

和:

args(){ echo [$1][$2]; }
args a   :b  # three spaces
# [a][ b]   

当有未引用的扩展时,应该总是发生分词。这里"$1"和$1是相同的,并且在这两种情况下它们都不使用:分隔符。[$2]->[ b]也不清楚。

可能在应用 IFS 拆分之前,使用了其他标记化规则,但我找不到它们。

variable arguments
  • 1 1 个回答
  • 1169 Views

1 个回答

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2017-12-04T14:36:03+08:002017-12-04T14:36:03+08:00

    分词仅适用于现代 Bourne-like shell 中的不带引号的扩展(参数扩展、算术扩展和命令替换)(在 中zsh,除非您使用仿真模式,否则仅命令替换)。

    当你这样做时:

    args a    :b
    

    完全不涉及分词。

    将这些标记化的是 shell 解析,发现第一个不是它的关键字之一,因此它是一个带有 3 个参数的简单命令args:a和:b. 那里的空间量不会有任何区别。请注意,它不仅是空格,还有制表符,并且在某些 shell(如yash或bash)中,任何在您的语言环境中被视为空白的字符(尽管在 的情况下bash,而不是多字节字符)¹。

    即使在 Bourne shell 中,无论它们是否是扩展的结果,分词也适用于命令的未引用参数,这将在标记化和语法解析的顶部(很久之后)完成。

    在 Bourne shell 中,在

    IFS=i
    while bib=did edit foo
    

    那不会将其解析为:

    "wh" "le b" "b=d" "d ed" "t foo"
    

    但首先作为while带有一个简单命令的a ,并且该简单命令的edit单词(因为它是一个参数,而不是bid=did作为赋值的单词)将被进一步拆分为edand ,t以便ed带有 3 个参数的命令ed,t并且foo将作为该while循环的条件。

    分词不是语法解析的一部分。它就像一个隐式应用于参数的运算符(也在for循环词、数组和一些 shell 中重定向的目标和一些其他上下文),用于它们中未引用的部分。令人困惑的是它是隐式完成的。你不做cmd split($x),你做cmd $x,并且split()(实际上glob(split()))是暗示的。在zsh中,您必须明确请求它进行参数扩展(split($x)是否$=x存在($=看起来像一把剪刀))。

    所以,现在,对于你的例子:

    args(){ echo ["$*"];}
    args a   :b  # three spaces
    # [a::b]
    

    a和:b参数argsjoin 与第一个字符$IFS给出a::b(请注意,[...]在这里使用它是一个坏主意,因为它是一个通配符运算符)。

    args(){ echo [$*];}
    args a   :b  # three spaces
    # [a  b]     # two spaces
    

    $*(其中包含a::b)被拆分为a、空字符串和b。所以是:

    echo '[a' '' 'b]'
    
    args(){ echo ["$1"]["$2"]; }
    args a   :b  # three spaces
    # [a][:b]
    

    毫不奇怪,因为没有分词。

    args(){ echo [$1][$2]; }
    args a   :b  # three spaces
    # [a][ b]   
    

    这就像:

     echo '[a]' '[' 'b]'
    

    as $2( :b) 将被拆分为空字符串和b.

    您将看到实现之间变化的一种情况是何时$IFS为空。

    在:

    set a b
    IFS=
    printf '<%s>\n' $*
    

    在某些 shell(现在大多数)中,您会看到

    <a>
    <b>
    

    <ab>即使不会"$*"扩展到ab. 这些外壳仍然将这些参数a和b位置参数分开,并且现在已在最新版本的标准中成为 POSIX 要求。

    如果你这样做了:

    set a b
    IFS=
    var="$*" # note that the behaviour for var=$* is unspecified
    printf '<%s>\n' $var
    

    您会看到<ab>分配给.ab$var


    ¹,当然,分隔单词的不仅仅是空格。shell 语法中的特殊标记也是如此,其列表取决于上下文。在大多数情况下,|, ||, &, ;, 换行符, <, >, >>... 分隔单词。例如ksh93,您可以编写一个无空白命令,例如:

    while({([[(:)]])})&&((1||1))do(:);uname<&2|tee>(rev)file;done
    
    • 12

相关问题

  • 变量值通过heredoc执行打印[关闭]

  • 如何在`zsh`中增加一个动态命名的变量

  • 需要许多参数的实用程序的推荐界面是什么?[关闭]

  • while 语句中的 Bash 或条件

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

Sidebar

Stats

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

    JSON数组使用jq来bash变量

    • 4 个回答
  • Marko Smith

    日期可以为 GMT 时区格式化当前时间吗?[复制]

    • 2 个回答
  • Marko Smith

    bash + 通过 bash 脚本从文件中读取变量和值

    • 4 个回答
  • Marko Smith

    如何复制目录并在同一命令中重命名它?

    • 4 个回答
  • Marko Smith

    ssh 连接。X11 连接因身份验证错误而被拒绝

    • 3 个回答
  • Marko Smith

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

    • 7 个回答
  • Marko Smith

    systemctl 命令在 RHEL 6 中不起作用

    • 3 个回答
  • Marko Smith

    rsync 端口 22 和 873 使用

    • 2 个回答
  • Marko Smith

    以 100% 的利用率捕捉 /dev/loop -- 没有可用空间

    • 1 个回答
  • Marko Smith

    jq 打印子对象中所有的键和值

    • 2 个回答
  • Martin Hope
    EHerman JSON数组使用jq来bash变量 2017-12-31 14:50:58 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Drux 日期可以为 GMT 时区格式化当前时间吗?[复制] 2017-12-26 11:35:07 +0800 CST
  • Martin Hope
    AllisonC 如何复制目录并在同一命令中重命名它? 2017-12-22 05:28:06 +0800 CST
  • Martin Hope
    Steve “root”用户的文件权限如何工作? 2017-12-22 02:46:01 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST
  • Martin Hope
    Cbhihe 将默认编辑器更改为 vim for _ sudo systemctl edit [unit-file] _ 2017-12-03 10:11:38 +0800 CST
  • Martin Hope
    showkey 如何下载软件包而不是使用 apt-get 命令安装它? 2017-12-03 02:15:02 +0800 CST
  • Martin Hope
    youxiao 为什么目录 /home、/usr、/var 等都具有相同的 inode 编号 (2)? 2017-12-02 05:33:41 +0800 CST
  • Martin Hope
    user223600 gpg —list-keys 命令在将私钥导入全新安装后输出 uid [未知] 2017-11-26 18:26:02 +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