在命令中重用或重复管道输入作为参数(给出示例)

时间:2013-06-07 04:09:08

标签: bash shell unix

我将用一个例子来解释这个问题。假设我想生成一个包含两列的列表。第1列包含文件名,第2列包含该文件的md5总和。

这可以使用以下脚本完成:

for FILE in `ls -p | grep -v "/"`;
do
    printf "%s %s\n" "$FILE" `md5 -q "$FILE"`;
done;

可以使用管道在一条线上完成吗?我尝试过使用sedxargsprintf的不同组合,但我认为我遗漏了一些东西。这是我的一次尝试:

ls -p | grep -v "/" | xargs -I FILE printf "%s %s\n" FILE `md5 -q FILE`

在那次尝试中,反引号中的FILE没有被替换,这并不奇怪。

这是我应该使用多行脚本的事情吗?由于没有逻辑或控制流程,我觉得应该有一个单行,也许我没有正确使用我的工具,或者我找不到合适的工具。

为标题道歉,我不知道该怎么称呼这个问题。

4 个答案:

答案 0 :(得分:6)

您可以使用md5sum,因为我没有md5:)

ls -p | grep -v / | xargs md5sum | awk '{print $2,$1}'

这可能是一种更安全,更健壮的方式:

find -maxdepth 1 -type f -exec md5sum {} \; | awk '{s=$2; $2=$1; $1=s;}1'

这应该适用于md5:

find -maxdepth 1 -type f -exec md5sum {} \; | sed 's/[^(]*(\([^)]*\)) =/\1/'

答案 1 :(得分:3)

怎么样:

ls *.cc | xargs -I FILE md5 FILE | sed 's/^MD5 (\(.*\)) =/\1/'

或者如果你担心文件名中的空格(我认为你不应该在任何情况下允许自己),

find . -name "*.cc" -maxdepth 1 | xargs -I FILE md5 FILE | sed 's/^MD5 (\(.*\)) =/\1/'

答案 2 :(得分:1)

ls -p | grep -v "/" | xargs -I FILE sh -c 'printf "%s %s\n" $0 `md5 -q $0`' FILE

您的代码无效,因为在将参数传递给xargs之前,原始shell会处理反引号。您需要通过将它们括在引号中来保护它们不被处理,然后将该参数传递给sh

然而,这似乎是一种糟糕的方式。它不适用于名称中包含空格的文件,grep是跳过目录的愚蠢方式。

for FILE in *
do
  if  [ -f "$FILE" ]
  then printf "%s %s\n" "$FILE" `md5 -q "$FILE"`
done

答案 3 :(得分:1)

要注意有关名称中包含奇怪字符的文件名,需要转义, EXCEPT "字符或带有md5总和和空格的文件名作为其名称的一部分:

find . -maxdepth 1 -type f  -print0 |xargs -0 -n1 -I{} bash -c 'echo -n "{} " ; cat "{}" |md5sum' | sed 's/ -$//'

使用cat使md5sum的文件名成为我们用-剥离的标准输入(sed)。但是,更改列的顺序不需要复杂的正则表达式,因为我们使用echo -n将文件名作为输出的第一列打印。

示例:

samveen@precise:/tmp/tmp.JpmDNkhcRG$ touch "ab'c"
samveen@precise:/tmp/tmp.JpmDNkhcRG$ touch "ab d41d8cd98f00b204e9800998ecf8427e c"
samveen@precise:/tmp/tmp.JpmDNkhcRG$ touch "ab c"
samveen@precise:/tmp/tmp.JpmDNkhcRG$ touch "abc"
samveen@precise:/tmp/tmp.JpmDNkhcRG$ touch "ab
> c"
samveen@precise:/tmp/tmp.JpmDNkhcRG$ touch "ab\!c"

samveen@precise:/tmp/tmp.JpmDNkhcRG$ find . -maxdepth 1 -type f  -print0 |xargs -0 -n1 -I{} bash -c 'echo -n "{} " ; cat "{}" |md5sum'| sed 's/ -$//'
./ab'c d41d8cd98f00b204e9800998ecf8427e
./ab d41d8cd98f00b204e9800998ecf8427e c d41d8cd98f00b204e9800998ecf8427e
./ab c d41d8cd98f00b204e9800998ecf8427e
./abc d41d8cd98f00b204e9800998ecf8427e
./ab
c d41d8cd98f00b204e9800998ecf8427e
./ab\!c d41d8cd98f00b204e9800998ecf8427e