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


441

我想将的结果ls -1合并为一行,并用我想要的任何内容定界。

我可以使用任何标准的Linux命令来实现此目的吗?

Answers:


689

与第一个选项相似,但省略了结尾的定界符

ls -1 | paste -sd "," -

29
只是要注意,我尝试粘贴的版本在末尾需要一个“-”参数来告诉它从STDIN中读取。例如,ls -1 | paste -s -d ":" - 不确定所有版本的糊剂是否通用
安迪·怀特

4
这个更好,因为它允许使用空定界符:)
Yura Purbeev

2
注意paste获取-(标准输入)作为默认,至少在我的paste (GNU coreutils) 8.22
fedorqui'SO停止伤害'

1
我刚刚投票赞成,现在它和所选答案具有相同的票数。这是答案。没有尾随的分隔符
thebugfinder

1
可以使用来指定空定界符"\0",所以paste -sd "\0" -对我有用!
布拉德·帕克斯

378

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

啊,力量和简单!

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

更改逗号“ ”你想要什么。请注意,这包括“尾随逗号”


46
+1,但更详尽的版本应以不同的方式处理最后一个\ n
mouviciel 2010年

5
如果文件名中包含一个\n,也将替换它。
codaddict

3
@ShreevatsaR:我相信他的意思是不要在结尾加上“”。像这样ls -1 | tr "\\n" "," | sed 's/\(.*\),/\1/'
克里斯

7
@克里斯:您sed可以使用结束标记字符来提高效率:ls -1 | tr "\\n" "," | sed 's/,$//'; echo ''
pieman72

2
使用sedafter tr似乎只是删除最后一个符号似乎是不合理的。我ls -1 | tr '\n' ',' | head -c -1
同意

29

这用换行符替换最后一个逗号:

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中使用readarray(aka mapfile):

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

感谢gniourf_gniourf的建议。


这将不会处理名称中带有空格的文件。试试这个:dir = / tmp / testdir; rm -rf $ dir && mkdir $ dir && cd / $ dir &&触摸“这是一个文件” this_is_another_file && ls -1 && files =($(ls -1))&& list = $ {files [@] /%/ ,} && list = $ {list%*,} && echo $ list
dimir 2014年

1
@dimir:这个问题的许多答案都受到这个问题的困扰。我已经编辑了答案,允许使用制表符或空格而不是换行符的文件名。
暂停,直到另行通知。

您的bash版本也遭受路径名扩展的困扰。为了建立从线的阵列,请考虑使用mapfile(击≥4)为:mapfile -t files < <(ls -1)。无需摆弄IFS。而且它也更短。
gniourf_gniourf 2014年

而且,当您拥有数组时,可以IFS用来加入以下字段:saveIFS=$IFS; IFS=,; list=${files[*]}; IFS=$saveIFS。或者,如果您要使用一个以上字符的分隔符,请使用另一种方法。
gniourf_gniourf 2014年

1
@gniourf_gniourf:我的回答中已经包括了您的建议。谢谢。
暂停,直到另行通知。

24

我觉得这很棒

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

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


6
这不排除尾部定界符。
德里克·马哈尔

6
这是特别真棒由于处理多字的记录分隔符(如" OR "
垫谢弗

15

设置IFS和使用的结合"$*"可以做您想要的。我使用的是子外壳,因此我不会干扰该外壳的$ IFS

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

要捕获输出,

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

2
您是否有更多有关set工作原理的信息?在我看来有点像巫毒教。浅看man set也没有给我太多信息。
Ehtesh Choudhury 2013年

3
如果给出set一堆参数但没有选项,它将设置位置参数($ 1,$ 2,...)。如果第一个参数(在这种情况下为文件名)恰好以短划线开头,--则可以保护set它。请参阅中有关--选项的说明help set。我发现位置参数是处理事物列表的便捷方法。我也可以使用数组来实现:output=$( files=(*); IFS=,; echo "${files[*]}" )
glenn jackman

这很棒,因为它不需要执行任何其他程序,并且可以处理包含空格甚至换行符的文件名。
埃里克(Eric)

1
@EhteshChoudhury如type set您所愿,set is a shell builtin。因此,man set将无济于事,但help set会做到的。答案:“-将其余所有参数分配给位置参数。”
斯特凡纳·古里科

过了一会儿set -- *。延迟*一级扩展,无需子shell即可获得正确的输出IFS=',' eval echo '"$*"'。当然,这将改变位置参数。
艾萨克(Isaac)


9

不要重新发明轮子。

ls -m

它确实做到了。


OP需要任何定界符,因此您仍然需要一个tr来转换逗号。它还在逗号后添加一个空格,即file1,file2,file3
rob

因此使用ls -mtr删除逗号后的空格就可以了ls -m | tr -d ' '
Andy

2
使用tr会删除文件名中的空格。更好地使用sed 's/, /,/g
格伦·杰克曼

7

只是扑

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

5
稍微更有效的方法是使用“ printf -v mystring”%s |“ *”-避免$()的
派生

但值得注意的是|,@ camh 不会让结尾处显得多余。
Christopher

1
好吧,公正bash和gnu coreutilsprintf
ThorSummoner 2015年

@camh但是printf -v仅适用于bash,而给出的答案适用于许多shell类型。
艾萨克(Isaac)

@Christopher是的,如果|同时使用了以下两行,它将删除尾部:printf -v mystring "%s|" * ; echo ${mystring%|}
艾萨克(Isaac)

7

此命令适用于PERL粉丝:

ls -1 | perl -l40pe0

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

-p将逐行处理并打印

-l将用我们提供的ascii字符替换尾随\ n。

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

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

perl -e0与perl -e''相同


6

为了避免tr可能引起的换行混乱,我们可以在-ls中添加-b标志:

ls -1b | tr '\n' ';'


5

除了majkinetor的答案之外,这是删除尾部定界符的方法(因为我还不能只在他的答案下发表评论):

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

只需删除定界符计数的尾随字节数即可。

我喜欢这种方法,因为我可以使用多字符定界符+的其他优点awk

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

编辑

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

首先,安装coreutils。“ GNU核心实用程序是GNU操作系统的基本文件,shell和文本操作实用程序。”

brew install coreutils

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

完成此操作后,您可以使用ghead哪个字节数为负,或者更好的是使用别名:

alias head="ghead"

注意:负字节数仅在某些版本的head上受支持,因此这不适用于macOS。
彼得

感谢您指出了这一点。我为MacOS添加了一种解决方法。
Aleksander Stelmaczonek,

4

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的答案以及其他一些类似的答案(例如here)为O(n²),因为每次将新行添加到模式空间中时,sed都必须替换。

比较,

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

3

如果您的xargs版本支持-d标志,则应该可以使用

ls  | xargs -d, -L 1 echo

-d是分隔符标志

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

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

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


3
-d使用GNU xargs指定输入定界符,因此将不起作用。第二个示例最后出现了与杂散定界符的其他解决方案相同的问题。
雷神

3
sed -e :a -e '/$/N; s/\n/\\n/; ta' [filename]

说明:

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

取自我的博客



2

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

这是另一个使用内置join函数的perl答案,该函数没有尾随定界符:

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

模糊的语言-0777使perl在运行程序之前先读取所有输入。

sed替代方法,不留下结尾定界符

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

0

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

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

用管道输送此结果以tr删除空格或逗号,将允许您再次输送管道tr以替换定界符。

在我的示例中,我用定界符替换,了定界符;

用您喜欢的;任何一个字符定界符替换,因为tr仅占您作为参数传递的字符串中的第一个字符。


0

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

perl -e'while(<>){如果(/ \ $ /){ } print;}'bad0> test

将换行符条件放在if语句中。它可以是特殊字符或任何定界符。


0

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

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

解释:

  • perl -E:在功能支持下执行Perl(例如,...)
  • 说:打印带有承运人退货
  • 加入“,”,ARRAY_HERE:以“,”加入阵列
  • 地图{chomp; $ _}行:从每一行中删除载体返回并返回结果
  • <>:stdin,每行是一个ROW,再加上一个映射,它将创建每个ROW的数组
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.