在 bash 中逐行交互添加参数

在 bash 中逐行交互添加参数

有时,我的剪贴板中有一个文件或字符串列表,并且希望将其作为参数列表粘贴到 bash shell 中:

示例文件列表(仅作为示例):

createsnapshot.sh
directorylisting.sh
fetchfile.sh

我想要的是:

md5sum createsnapshot.sh directorylisting.sh fetchfile.sh

目前,我输入以下 hacky 命令行(文件名是从剪贴板粘贴的;列表可以包含几十行):

md5sum $(echo $(echo "
createsnapshot.sh
directorylisting.sh
fetchfile.sh
"))

这有几个缺点:

  • 这很复杂
  • 看起来不太好
  • 它不支持包含空格的行

我还有什么其他选择?md5sum "不起作用,因为在这种情况下我只得到一个带有多行字符串的参数。与此处文档类似。

并不总是如此md5sum。也可以是targit adddu -hsc。我不只是要求一种方法来获取这些文件的 md5 校验和。这样的情况每天大约会发生2-5次。

答案1

如果您不引用变量或虚拟变量,例如反引号调用(例如$(xclip -selection c -o)(输出 X 剪贴板的内容)),则 shell 将拆分 $IFS默认为\t \n和 的内容,并且它将扩展内容中存在的全局变量。在这种情况下(确保您首先检查剪贴板的内容),这就是您想要的:

md5sum `xclip -selection c -o`

笔记:

在您需要的命令周围有一个简短命名的包装器非常方便xclip

我用

#!/bin/sh
#filename: cb
if [ -n "$DISPLAY" ]; then
    [ -t 0 ] && exec /usr/bin/xclip -selection c -o 2>/dev/null
    /usr/bin/xclip -selection c
else
    [ -t 0 ] && exec cat "/dev/shm/$TTY_DASHED"
    cat > /dev/shm/"$TTY_DASHED"
fi

这允许我输入内容cb来访问剪贴板并something | cb写入内容。

DISPLAY(如果我在 X 之外(=如果未设置),我会使用以我的终端命名的内存中文件作为我的剪贴板。env 变量在我的as withTTY_DASHED中设置 ).profileexport TTY_DASHED=$(tty |tr / - | tail -c+2)

答案2

如果命令不使用 use stdin,请使用xargs,它读取输入并将其转换为参数(请注意,我使用该echo命令来展示如何xargs构建该命令):

$ xargs echo md5sum
# paste text
createsnapshot.sh
directorylisting.sh
fetchfile.sh
# press Ctrl-D to signify end of input
md5sum createsnapshot.sh directorylisting.sh fetchfile.sh

使用xargswith -d '\n',以便将每一行视为一个完整的参数,尽管有空格:

$ xargs -d'\n' md5sum
# paste
a file with spaces
afilewithoutspaces
foo " " bar
# Ctrl D
md5sum: a file with spaces: No such file or directory
md5sum: afilewithoutspaces: No such file or directory
md5sum: foo " " bar: No such file or directory

如您所见,md5sum无论文件名中的其他空格如何,都会打印每个文件名的错误。

如果您愿意使用xclip,那么您可以通过管道或其他方式将其提供给 xargs:

xargs -a <(xclip -o) -d '\n' md5sum
xclip -o | xargs -d '\n' md5sum

这应该可以可靠地处理带有空格的文件名。

答案3

您可以设置一个包含文件名的变量。然后在命令中使用该变量。

$ #VAR='<paste filenames>':
$ VAR='createsnapshot.sh
>  directorylisting.sh
> fetchfile.sh'

$ touch $VAR
$ ls -l $VAR
-rw-r--r-- 1 testuser testuser 0 nov 26 12:47 createsnapshot.sh
-rw-r--r-- 1 testuser testuser 0 nov 26 12:47 directorylisting.sh
-rw-r--r-- 1 testuser testuser 0 nov 26 12:47 fetchfile.sh

$ md5sum $VAR
d41d8cd98f00b204e9800998ecf8427e  createsnapshot.sh
d41d8cd98f00b204e9800998ecf8427e  directorylisting.sh
d41d8cd98f00b204e9800998ecf8427e  fetchfile.sh

$ tar cf archive.tar $VAR
$ tar tf archive.tar
createsnapshot.sh
directorylisting.sh
fetchfile.sh

注意:$VAR由于行结尾,需要在不带引号的情况下调用。您可以考虑使用VAR=$(echo "$VAR"|tr '\n' ' ') to be able to use quoted$VAR`

另一种方法(基于上述)是在您的~/.bashrc包含中编写一个函数:

fVAR () 
{ 
    VAR="$@";
    VAR=$(echo "$VAR"|tr '\n' ' ')
}

使用剪贴板内容调用该函数fVAR,值可在以下位置找到$VAR

$ fVAR '<paste filenames>'
$ md5sum "$VAR"

答案4

set --
while IFS= read -r in
do    set -- "$@" "$in"
done

...然后按您的移位插入键,然后Ctrl+D一次(或两次),然后你的粘贴的每一行都可以被逐字地拥有(无 NUL)in$1$2等等$3,并且整个输入数组可以作为连接在$IFSin的第一个字符上的单个字符串进行寻址"$*",或者作为 in 的单独字符串列表进行寻址"$@",这意味着您可以执行以下操作:

md5sum -- "$@"

...因为您显然正在寻找有用的交互式速记:

alias rdcb='
    [ -t 0 ] && set -- &&
    while IFS= read -r in
    do    set -- "$@" "$in"
    done'

...将定义一个alias可以在交互式 shell 中运行的命令,以将 shell 的参数设置为来自标准输入的换行符分隔数组。

所以...

{   ls -1 | xsel -bi                 #pipes ls output into my clipboard
    rdcb                             #terminal hangs, shift+insert && crtl+d
    xsel -bo                         #writes my clipboard to stdout
    printf %s\\n '' --- '' "$@"      #writes \n-delimited shell arg array
    printf %s\\n '' --- '' "$3" "$5" #writes only args "$3" and "$5"
}

1
edit.sh
paccache
sh
systemd-private-75115542eb544b09bc245e8ca7765854-systemd-timesyncd.service-CKruFk
sztally
yaourt-tmp-mikeserv

---

1
edit.sh
paccache
sh
systemd-private-75115542eb544b09bc245e8ca7765854-systemd-timesyncd.service-CKruFk
sztally
yaourt-tmp-mikeserv

---

paccache
systemd-private-75115542eb544b09bc245e8ca7765854-systemd-timesyncd.service-CKruFk

这是一个更好的版本:

alias rdcb='
    if    [ -t 0 ]
    then  set -f -- "$IFS" "${IFS+IFS=\$1;} set +f -$-
          stty $(stty -g; stty raw -echo min 1 time 2)"
          IFS=$(printf \\r)
          set -- "$@" $(dd bs=4k count=1 2>/dev/null)
          eval "unset IFS;$2;shift 2"
    fi '

它放弃了终端回显和终端特殊字符处理,并且不需要CTRL+D表示输入结束。它所做的所有事情都是临时的,并且它会小心地将它影响的所有设置恢复到完成时发现它们的状态,除了 shell 的参数,当然,这些参数是根据设计而永久更改的。

因此,您只需执行此操作rdcb,然后粘贴即可完成。当您粘贴时,屏幕上不会有任何输出 - 终端将挂起,然后您在十分之一秒内输入至少一个字节,提示将重新出现。之后,您可以像以前一样处理参数。

相关内容