如何在bash中将一行文本按一个或多个空格分割为单词?

67

我知道如何在Python中实现它,只需要使用

line = db_file.readline()
ll=string.split(line)

但是我该如何在bash中实现相同的操作呢?真的有可能用一种如此简单的方式来做吗?


我认为您在Python中的意思是ll=str.split(line) - Arthur
9个回答

154
s='foo bar baz'
a=( $s )
echo ${a[0]}
echo ${a[1]}
...

1
内联变量:BAR =“$(a =($ value); echo $ {a [1]})” - Austin France
1
这会产生一个错误./deploy.sh: 7: ./deploy.sh: 语法错误: "(" 意外第7行是指,a=($s)所在的位置。 - Isuru Pathirana
3
这个语法是专门针对Bash的;如果你的脚本不是由Bash执行(例如在Debian或Ubuntu系统上以#!/bin/sh开头),就会出现语法错误。如果像这样执行脚本bash deploy.sh,或者将第一行改为#!/usr/bin/env bash,它应该可以工作。 - ZoogieZork
4
如果你只想从(例如)一个命令的输出中提取第一个或最后一个单词,你可以简单地使用shell变量字符串替换运算符来删除字符串的第一个或最后一个部分。`desktop:~$ var="first last" desktop:~$ first_word=${var%% *} # 空格星号 ! desktop:~$ echo $first_word first desktop:~$ last_word=${var##* } # 星号空格 ! desktop:~$ echo $last_word last` - MikeW
如果输入包含通配符字符,例如s='foo bar baz'尝试s='* bar baz',则此方法会失败。 - bitinerant

52

如果你想从一行中获取特定的单词,awk 可以帮到你,例如:

$ echo $LINE | awk '{print $2}'

上述命令会输出 $LINE 中第二个由空格分隔的单词。你也可以使用其他字符进行分割,例如:

$ echo "5:6:7" | awk -F: '{print $2}'
6

1
这是我现在开始使用awk的原因。与数组创建和额外的行不同,-F:只需在一行中从:中分离。喜欢它,谢谢。 - m3nda
此外:echo "5::6:7" | awk -F:: '{print $2}' 输出 6:7 (与只取一个字符作为分隔符的 cut 不同) - ribamar

41
echo $line | tr " " "\n"

不使用循环,提供与上面大多数答案类似的输出。




在您的情况下,您还提到了ll=<...output...>, 因此(假设我不太懂Python并且假设您需要将输出分配给一个变量),

ll=`echo $line | tr " " "\n"`

应该足够了(记得使用echo "$ll"而不是echo $ll


40

这要取决于你所说的“split”的含义。如果你想迭代变量中一行中的单词,你只需进行迭代即可。例如,假设变量linethis is a line,那么你可以这样做:

for word in $line; do echo $word; done

这将打印:

this
is
a
line

for .. in $var 语法使用变量 $var 中的值,使用默认的 $IFS 变量来分割字符串,其中默认值表示“按照空格和换行符进行分割”。

如果你想要从用户或文件中读取行,可以像这样做:

cat $filename | while read line
do
    echo "Processing new line" >/dev/tty
    for word in $line
    do
        echo $word
    done
done

如果您还有其他问题,您需要更加明确并详细地定义您的问题。

注意:已编辑以删除bashism,但我仍然保留了cat $filename | ...,因为我比重定向更喜欢它。


6
不必要使用cat - 可以这样重定向文件:done < "$filename"。此外,在这种情况下,请使用for value in "${var[@]}"而不是索引变量。虽然在这种情况下数组可能是连续的,但Bash支持稀疏数组,${#var[@]}可能不是最后一个条目(尽管${var[@]: -1}将是最后一个条目,indices=(${!a[@]}); count=${#indices[@]}将给出索引列表和正确的计数)。 - Dennis Williamson
1
@Dennis:所有的观点都很好。出于某种原因,我习惯于使用cat a | blah而不是`blah <a';但其他观点也很有道理。 - Alok Singhal
2
如果在$line中有一个星号(*),这种方法将会失败。Bash会用当前目录中的文件列表替换它。 - crenate

12

做这个

while read -r line
do
  set -- $line
  echo "$1 $2"
done <"file"

$1、$2等将是您分割后的第一和第二个“字段”。使用$@获取所有值,使用$#获取“字段”的长度。


1
请注意,如果您的$line包含例如*,则在执行set -- $line时,bash将对其进行扩展,这可能会产生令人惊讶的影响。 - clacke
1
  1. "--"是什么作用?
  2. 扩展*有哪些令人惊讶的效果?
- Xofo

12

更加简单易懂,

echo $line | sed 's/\s/\n/g'

\s --> 空白字符(空格、制表符、换行符、换页符、垂直制表符、回车符)。在许多系统中也有效的[:space:]

\n --> 换行符


这会将每个空格字符转换为自己的新行,对吗? - Eliezer Miron

10
$ line="these are words"
$ ll=($line)
$ declare -p ll  # dump the array
declare -a ll='([0]="these" [1]="are" [2]="words")'
$ for w in ${ll[@]}; do echo $w; done
these
are
words

1
+1 教我使用 -p 选项 - grok12

6

-a选项可以让read按照$IFS中包含的字符分割读取的行。


#!/bin/bashfilename=$1while read LINE do echo $LINE | read -a done < $filename这段代码是否能够正常工作? - asdf
不,-a 将是第一个 read 的参数。“help read” 在 bash 命令行上会有帮助。 - Ignacio Vazquez-Abrams
2
@asdf:它看起来像这样:filename=$1; while read -a LINE; do echo "$LINE"; done < "$filename" - Dennis Williamson

4
如果您已经将文本存储在变量$LINE中,那么您应该能够执行以下操作:
for L in $LINE; do
   echo $L;
done

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接