如何使用自定义分隔符将多行文件名合并为一行

How to join multiple lines of filenames into one with custom delimiter

提问人:JavaRocky 提问时间:5/4/2010 最后编辑:Mateen UlhaqJavaRocky 更新时间:2/20/2023 访问量:306570

问:

如何将结果合并为一行并用我想要的任何内容分隔它?ls -1

Linux 字符串 bash shell 解析

评论


答:

4赞 Chris J 5/4/2010 #1

如果您的 xargs 版本支持 -d 标志,那么这应该有效

ls  | xargs -d, -L 1 echo

-d 是分隔符标志

如果您没有 -d,则可以尝试以下操作

ls | xargs -I {} echo {}, | xargs echo

第一个 xargs 允许您指定分隔符,在此示例中为逗号。

评论

3赞 Thor 9/13/2012
-d使用 GNU xargs 指定输入分隔符,因此不起作用。第二个示例与此处的其他解决方案存在相同的问题,即末尾的杂散分隔符。
418赞 zaf 5/4/2010 #2

编辑:只需“ls -m”,如果您希望分隔符是逗号

啊,强大而简单!

ls -1 | tr '\n' ','

将逗号“”更改为您想要的任何内容。请注意,这包括一个“尾随逗号”(对于以换行符结尾的列表)

评论

51赞 mouviciel 5/4/2010
+1,但更复杂的版本应该以不同的方式处理最后 \n
6赞 codaddict 5/4/2010
如果文件名中包含 a,这也将替换它。\n
3赞 Chris 3/9/2012
@ShreevatsaR:他的意思是不要附加尾随的“,”我相信。这样ls -1 | tr "\\n" "," | sed 's/\(.*\),/\1/'
7赞 pieman72 12/17/2013
@Chris:使用结束标记字符可以更有效率:sedls -1 | tr "\\n" "," | sed 's/,$//'; echo ''
7赞 reddot 3/8/2019
使用 after 似乎只是删除最后一个符号似乎不合理。我和sedtrls -1 | tr '\n' ',' | head -c -1
1赞 codaddict 5/4/2010 #3

您可以使用:

ls -1 | perl -pe 's/\n$/some_delimiter/'

评论

1赞 Derek Mahar 11/21/2014
这并不排除尾随分隔符。
6赞 yabt 5/4/2010 #4

为了避免 tr 的潜在换行符混淆,我们可以在 ls 中添加 -b 标志:

ls -1b | tr '\n' ';'
39赞 Dennis Williamson 5/4/2010 #5

这会将最后一个逗号替换为换行符:

ls -1 | tr '\n' ',' | sed 's/,$/\n/'

ls -m在屏幕宽度字符处包含换行符(例如第 80 个)。

主要是 Bash(只有外部):ls

saveIFS=$IFS; IFS=$'\n'
files=($(ls -1))
IFS=,
list=${files[*]}
IFS=$saveIFS

在 Bash 4 中使用(aka ):readarraymapfile

readarray -t files < <(ls -1)
saveIFS=$IFS
IFS=,
list=${files[*]}
IFS=$saveIFS

感谢gniourf_gniourf的建议。

评论

0赞 dimir 10/23/2014
这不会处理名称中带有空格的文件。试试这个: dir=/tmp/testdir;rm -rf $dir && mkdir $dir && cd /$dir & touch “This is a file” this_is_another_file && ls -1 && files=($(ls -1)) && list=${files[@]/%/,} && list=${list%*,} && echo $list
1赞 Dennis Williamson 10/23/2014
@dimir:这个问题的许多答案都存在这个问题。我已经编辑了我的答案,以允许带有制表符或空格的文件名,但不允许使用换行符。
0赞 gniourf_gniourf 10/24/2014
您的 bash 版本也受到路径名扩展的影响。要从行构建数组,请考虑使用 (Bash ≥4) 作为: .无需摆弄.而且它也更短。mapfilemapfile -t files < <(ls -1)IFS
0赞 gniourf_gniourf 10/24/2014
当你有你的数组时,你可以用它来连接字段:.或者,如果您想要一个包含多个字符的分隔符,请使用另一种方法。IFSsaveIFS=$IFS; IFS=,; list=${files[*]}; IFS=$saveIFS
1赞 Dennis Williamson 10/24/2014
@gniourf_gniourf:我已经在回答中包含了你的建议。谢谢。
8赞 ghostdog74 5/4/2010 #6

只是 bash

mystring=$(printf "%s|" *)
echo ${mystring%|}

评论

5赞 camh 5/9/2010
稍微更有效的是使用 “printf -v mystring ”%s|“ *” - 这样可以避免 $() 的分叉
0赞 Christopher 6/2/2015
但值得注意的是,它不会扼杀尾随的,@camh。|
1赞 ThorSummoner 10/9/2015
好吧,just 和 gnu coreutilsbashprintf
0赞 2/1/2017
@camh 但仅适用于 bash,而给出的答案适用于许多 shell 类型。printf -v
0赞 2/1/2017
@Christopher 是的,这将删除尾随 ,前提是使用两行: .|printf -v mystring "%s|" * ; echo ${mystring%|}
15赞 glenn jackman 5/6/2011 #7

设置和使用的结合可以做你想做的事。我正在使用一个子 shell,所以我不会干扰这个 shell 的$IFSIFS"$*"

(set -- *; IFS=,; echo "$*")

要捕获输出,

output=$(set -- *; IFS=,; echo "$*")

评论

2赞 Ehtesh Choudhury 9/13/2013
您有更多关于工作原理的信息吗?在我看来有点像巫毒教。浅薄的浏览也没有给我带来太多信息。setman set
3赞 glenn jackman 9/13/2013
如果你给出了一堆参数但没有选项,它会设置位置参数($1、$2 等)。 如果第一个参数(或在这种情况下的文件名)碰巧以破折号开头,可以保护。请参见中的选项说明。我发现位置参数是处理事物列表的便捷方法。我也可以通过数组来实现这一点:set--set--help setoutput=$( files=(*); IFS=,; echo "${files[*]}" )
0赞 Eric 1/22/2015
这很棒,因为它不需要执行任何其他程序,并且它适用于包含空格甚至换行符的文件名。
1赞 Stéphane Gourichon 3/30/2016
@EhteshChoudhury 正如会告诉你的,.所以,无济于事,但会做。 答:“-- 将任何剩余的参数分配给位置参数。type setset is a shell builtinman sethelp set
0赞 2/1/2017
在 .延迟一个级别的扩展,您可以在不需要子外壳的情况下获得正确的输出: .当然,这将改变位置参数。set -- **IFS=',' eval echo '"$*"'
873赞 Artem 7/1/2011 #8

paste -s -d使用分隔符连接行(例如 ),并且不留下尾随分隔符:","

ls -1 | paste -sd "," -

评论

36赞 Andy White 5/11/2012
请注意,我尝试的粘贴版本需要在末尾使用“-”参数来告诉它从 STDIN 读取。例如 不确定这是否适用于所有版本的粘贴ls -1 | paste -s -d ":" -
5赞 iururu 8/16/2014
这个更好,因为它允许空分隔符:)
2赞 fedorqui 7/29/2015
注意 gets (standard input) 作为默认值,至少在我的 .paste-paste (GNU coreutils) 8.22
2赞 thebugfinder 9/14/2015
我刚刚给它投了赞成票,这是,现在它与所选答案具有相同的票数。这就是答案。无尾随定距
1赞 Brad Parks 12/18/2015
空分隔符可以使用 指定,所以对我有用!"\0"paste -sd "\0" -
2赞 Thor 9/13/2012 #9

ls当连接到管道时,会产生一个列输出,因此是冗余的。-1

这是另一个使用内置函数的 perl 答案,它不会留下尾随分隔符:join

ls | perl -F'\n' -0777 -anE 'say join ",", @F'

晦涩难懂使 perl 在运行程序之前读取所有输入。-0777

不留下尾随分隔符的 sed 替代方案

ls | sed '$!s/$/,/' | tr -d '\n'
34赞 majkinetor 12/14/2012 #10

我觉得这个太棒了

ls -1 | awk 'ORS=","'

ORS 是“输出记录分隔符”,因此现在您的行将用逗号连接。

评论

14赞 Derek Mahar 11/21/2014
这并不排除尾随分隔符。
8赞 Mat Schaffer 11/16/2016
由于处理多字符记录分隔符(例如," OR ")
8赞 Sidharth C. Nadhan 4/3/2013 #11

此命令适用于 PERL 粉丝:

ls -1 | perl -l40pe0

这里 40 是空间的八进制 ascii 代码。

-p 将逐行处理并打印

-l 将负责将尾部 \n 替换为我们提供的 ASCII 字符。

-e 是通知 PERL 我们正在执行命令行。

0 表示实际上没有要执行的命令。

perl -e0 与 perl -e ' ' 相同

9赞 Tulains Córdova 4/16/2013 #12

不要重新发明轮子。

ls -m

它正是这样做的。

评论

0赞 rob 4/26/2013
OP 需要任何分隔符,因此您仍然需要 tr 来转换逗号。它还会在逗号后添加一个空格,即 file1、file2、file3
0赞 Andrew 4/30/2013
因此,使用 和 删除逗号后面的空格,你会做的ls -mtrls -m | tr -d ' '
2赞 glenn jackman 5/7/2013
使用 TR 将删除文件名中的空格。更好用sed 's/, /,/g
0赞 Andrew 4/30/2013 #13

ls可以选择用逗号和空格分隔输出。-m", "

ls -m | tr -d ' ' | tr ',' ';'

通过管道将此结果用于删除空格或逗号,将允许您再次通过管道将结果用于替换分隔符。trtr

在我的示例中,我将分隔符替换为分隔符,;

替换为您喜欢的任何一个字符分隔符,因为 tr 只考虑您作为参数传入的字符串中的第一个字符。;

5赞 Anand Rajasekar 8/20/2014 #14
sed -e :a -e '/$/N; s/\n/\\n/; ta' [filename]

解释:

-e- 表示要执行
的命令 - 是一个标签 - 定义当前和 (N)ext 行
的匹配范围 - 将
所有 EOL 替换为 - 如果匹配成功,则转到标签
A
:a/$/Ns/\n/\\n/;\nta;

摘自我的博客

19赞 kenorb 5/30/2015 #15

一般不建议解析,因此另一种更好的方法是使用 ,例如:lsfind

find . -type f -print0 | tr '\0' ','

或者通过使用 和 :findpaste

find . -type f | paste -d, -s

对于一般的多行连接(与文件系统无关),请查看:Unix 命令行上的简洁且可移植的“连接”。

评论

0赞 RonJohn 11/3/2023
虽然为 true,但其他示例对于要合并为一行的任何列表都是通用的。
0赞 Suman 4/27/2016 #16

您可以使用 chomp 将多行合并为一行:

perl -e 'while (<>) { if (/\$/ ) { chomp; } print ;}' bad0 >测试

在 if 语句中放置换行符条件。它可以是特殊字符或任何分隔符。

6赞 plhn 12/28/2016 #17

看起来答案已经存在。

如果需要格式,请使用 ( Tulains Córdova 的回答a, b, cls -m)

或者,如果您想要格式,请使用(Chris J 答案的简化版本a b cls | xargs)

或者,如果您想要任何其他分隔符,例如 ,请使用 (应用 Artem 的答案|ls | paste -sd'|')

12赞 Aleksander Stelmaczonek 4/3/2017 #18

在 majkinetor 的答案之上,这是删除尾随分隔符的方法(因为我还不能在他的答案下发表评论):

ls -1 | awk 'ORS=","' | head -c -1

只需删除分隔符所计数的尾随字节即可。

我喜欢这种方法,因为我可以使用多字符分隔符 + 以下其他好处:awk

ls -1 | awk 'ORS=", "' | head -c -2

编辑

正如 Peter 所注意到的,本机 MacOS 版本的 head 不支持负字节计数。但是,这很容易解决。

首先,安装 .“GNU Core Utilities 是 GNU 操作系统的基本文件、外壳和文本操作实用程序。”coreutils

brew install coreutils

MacOS 提供的命令也以前缀“g”安装。例如。gls

完成此操作后,您可以使用具有负字节数的 let,或者更好的是,make alias:ghead

alias head="ghead"

评论

1赞 Peter 2/5/2019
注意:负字节数仅在某些版本的 head 上受支持,因此这在 macos 上不起作用。
0赞 Aleksander Stelmaczonek 2/6/2019
谢谢你指出这一点。我为 MacOS 添加了一种解决方法。
6赞 zhazha 1/28/2018 #19

sed方式,

sed -e ':a; N; $!ba; s/\n/,/g'
  # :a         # label called 'a'
  # N          # append next line into Pattern Space (see info sed)
  # $!ba       # if it's the last line ($) do not (!) jump to (b) label :a (a) - break loop
  # s/\n/,/g   # any substitution you want

注意

这在复杂性上是线性的,在将所有行附加到 sed 的模式空间后,只替换一次。

@AnandRajaseka 的答案,以及其他一些类似的答案,比如这里,是 O(n²),因为每次将新行附加到模式空间时,sed 都必须做 substitute。

为了比较,

seq 1 100000 | sed ':a; N; $!ba; s/\n/,/g' | head -c 80
  # linear, in less than 0.1s
seq 1 100000 | sed ':a; /$/N; s/\n/,/; ta' | head -c 80
  # quadratic, hung
0赞 Celogeek San 6/12/2019 #20

带有尾部斜杠处理的快速 Perl 版本:

ls -1 | perl -E 'say join ", ", map {chomp; $_} <>'

解释一下:

  • perl -E:执行具有功能支持的 Perl(比如说,...)
  • 说:打印承运人退货
  • join “, ”, ARRAY_HERE:用 “, ” 连接数组
  • map {chomp; $_} ROWS:从每一行中删除载体返回并返回结果
  • <>:stdin,每行都是一个 ROW,与 map 耦合它将创建每个 ROW 的数组

评论

0赞 drjumper 11/12/2022
按应有的方式工作。
1赞 brtknr 8/5/2020 #21

如果 Python3 是你的菜,你可以这样做(但请解释你为什么要这样做?

ls -1 | python -c "import sys; print(','.join(sys.stdin.read().splitlines()))"

评论

0赞 cmoran92 8/30/2020
我不知道 OP 为什么要这样做,但我知道我为什么需要这样做:为了复制所有用空格分隔的文件名,将它们用作 rubocop、eslint、stylelint、haml-lint 等的参数。
2赞 Joel Franco Guzmán 9/11/2020 #22

上面的 Python 答案很有趣,但自己的语言甚至可以使输出变得漂亮:

ls -1 |python -c “导入系统;打印(sys.stdin.read().splitlines())”

评论

0赞 Ciro Santilli OurBigBook.com 8/3/2022
我简直不敢相信 Python oneliner 是我能找到的多字符分隔符的最佳方式......但它是:.POSIX再次让我失望了。python -c "import sys; print(' | '.join(sys.stdin.read().splitlines()))"