ChatGPT解决这个技术问题 Extra ChatGPT

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

我想将 ls -1 的结果加入一行并用我想要的任何内容进行分隔。

我可以使用任何标准的 Linux 命令来实现这一点吗?


j
jpbochi

类似于第一个选项,但省略了尾随分隔符

ls -1 | paste -sd "," -

就像注释一样,我尝试的粘贴版本在末尾需要一个“-”参数来告诉它从 STDIN 读取。例如 ls -1 | paste -s -d ":" - 不确定这是否适用于所有版本的粘贴
这个更好,因为它允许空分隔符:)
注意 paste 获取 -(标准输入)作为默认值,至少在我的 paste (GNU coreutils) 8.22 上。
我刚刚投了赞成票,这是现在它与所选答案的票数相同。这就是答案。没有尾随分隔符
可以使用 "\0" 指定空分隔符,因此 paste -sd "\0" - 对我有用!
r
rogerdpack

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

啊,力量和简单!

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

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


+1,但更复杂的版本应该以不同的方式处理 last \n
如果文件名中包含 \n,这也将替换它。
@ShreevatsaR:我相信他的意思是不附加尾随的“,”。像这样ls -1 | tr "\\n" "," | sed 's/\(.*\),/\1/'
@Chris:您的 sed 使用结束标记字符可能会更有效率:ls -1 | tr "\\n" "," | sed 's/,$//'; echo ''
tr 之后使用 sed 似乎只是删除最后一个符号似乎不合理。我和ls -1 | tr '\n' ',' | head -c -1一起去
D
Dennis Williamson

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

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(又名 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 && touch "这是一个文件" this_is_another_file && ls -1 && files=($(ls -1)) && list=${files[@]/%/ ,} && list=${list%*,} && echo $list
@dimir:这个问题的许多答案都受到这个问题的困扰。我已经编辑了我的答案以允许使用制表符或空格的文件名,但不允许使用换行符。
您的 bash 版本也受到路径名扩展的影响。要从行构建数组,请考虑使用 mapfile (Bash ≥4) 作为:mapfile -t files < <(ls -1)。无需摆弄 IFS。而且它也更短。
当您拥有阵列时,您可以使用 IFS 加入字段:saveIFS=$IFS; IFS=,; list=${files[*]}; IFS=$saveIFS。或者,如果您想要一个包含多个字符的分隔符,请使用另一种方法。
@gniourf_gniourf:我的回答中包含了您的建议。谢谢。
r
rogerdpack

我觉得这个很棒

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

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


这不排除尾随分隔符。
由于处理多字符记录分隔符(例如," OR "),这特别棒
C
Community

解析 ls 一般为 is not advised,因此另一种更好的方法是使用 find,例如:

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

或使用 findpaste

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

对于一般连接多行(与文件系统无关),请检查:Concise and portable “join” on the Unix command-line


g
glenn jackman

设置 IFS 和使用 "$*" 的组合可以做你想做的事。我正在使用子外壳,所以我不会干扰这个外壳的 $IFS

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

要捕获输出,

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

您是否有更多关于 set 工作原理的信息?对我来说有点像巫毒。通过 man set 的浅薄观察也没有为我提供太多信息。
如果您给 set 一堆参数但没有选项,它会设置位置参数($1,$2,...)。 -- 用于保护 set,以防第一个参数(或本例中的文件名)碰巧以破折号开头。请参阅 help set-- 选项的说明。我发现位置参数是一种处理事物列表的便捷方式。我也可以用一个数组来实现这个:output=$( files=(*); IFS=,; echo "${files[*]}" )
这很棒,因为它不需要执行任何额外的程序,并且它适用于包含空格甚至换行符的文件名。
@EhteshChoudhury type set 会告诉你,set is a shell builtin。因此,man set 无济于事,但 help set 会。答案:“-- 将任何剩余的参数分配给位置参数。”
set -- * 之后。将 * 的扩展延迟一级,您可以在不需要子 shell 的情况下获得正确的输出:IFS=',' eval echo '"$*"'。当然,这会改变位置参数。
A
Aleksander Stelmaczonek

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

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

只需删除与分隔符一样多的尾随字节即可。

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

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

编辑

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

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

brew install coreutils

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

完成此操作后,您可以使用具有负字节数的 ghead,或者更好地使用别名:

alias head="ghead"

注意:负字节计数仅在某些版本的 head 上支持,因此这不适用于例如 macos。
感谢您指出了这一点。我为 MacOS 添加了一个解决方法。
T
Tulains Córdova

不要重新发明轮子。

ls -m

它正是这样做的。


OP 想要任何分隔符,所以你仍然需要一个 tr 来转换逗号。它还在逗号后添加一个空格,即 file1、file2、file3
所以使用 ls -mtr 删除逗号后的空格,你会做 ls -m | tr -d ' '
使用 tr 将删除文件名中的空格。更好地使用sed 's/, /,/g
g
ghostdog74

只是猛击

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

稍微更有效的是使用 "printf -v mystring "%s|" *" - 这避免了 $() 的分叉
但值得注意的是,它不会破坏尾随的 |,@camh。
好吧,只有 bash 和 gnu coreutils printf
@camh 但是 printf -v 仅适用于 bash,而提供的答案适用于许多 shell 类型。
@Christopher 是的,这将删除尾随的 |,前提是使用两行:printf -v mystring "%s|" * ; echo ${mystring%|}
S
Sidharth C. Nadhan

此命令适用于 PERL 粉丝:

ls -1 | perl -l40pe0

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

-p 将逐行处理并打印

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

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

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

perl -e0 与 perl -e ' ' 相同


y
yabt

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

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

C
Community

看起来答案已经存在。

如果您想要 a, b, c 格式,请使用 ls -m ( Tulains Córdova’s answer)

或者,如果您想要 a b c 格式,请使用 ls | xargsChris J’s answer 的简化版本)

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


z
zhazha

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 的 answer 和其他一些类似的答案,例如 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

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

解释:

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

取自 my blog


C
Chris J

如果您的 xargs 版本支持 -d 标志,那么这应该可以工作

ls  | xargs -d, -L 1 echo

-d 是分隔符标志

如果你没有-d,那么你可以试试下面的

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

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


-d 使用 GNU xargs 指定输入分隔符,因此不起作用。第二个示例展示了与此处的其他解决方案相同的问题,即末尾的杂散定界符。
c
codaddict

您可以使用:

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

这不排除尾随分隔符。
T
Thor

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

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

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

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

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

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

A
Andrew

ls 有选项 -m", " 逗号和空格分隔输出。

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

将此结果传送到 tr 以删除空格或逗号将允许您再次将结果传送到 tr 以替换分隔符。

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

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


S
Suman

您可以使用 chomp 在单行中合并多行:

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

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


b
brtknr

如果 Python3 是您的首选,您可以这样做(但请解释一下为什么要这样做?):

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

我不知道为什么 OP 想要这样做,但我知道我为什么需要这样做:为了复制所有由空格分隔的文件名,以将它们用作 rubocop、eslint、stylelint、haml-lint 的参数,等等
J
Joel Franco Guzmán

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

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


C
Celogeek San

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

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

解释:

perl -E:执行带有特性支持的 Perl(比如,...)

说:打印与承运人退货

join ", ", ARRAY_HERE: 用 ", " 加入数组

地图 {chomp; $_} ROWS:从每行移除运营商返回并返回结果

<>:stdin,每一行都是一个ROW,加上一个map会为每个ROW创建一个数组