0

这些行在复制粘贴到 shell 时有效,但在脚本中无效:

ls -l file1 > /path/`echo !#:2`.txt
ls -l file2 > /path/`echo !#:2`.txt

 

ls -l file1 > /path/$(echo !#:2).txt
ls -l file2 > /path/$(echo !#:2).txt

在 bash 脚本中执行此操作的语法是什么?

如果可能的话,我想知道如何对一个文件以及文件夹中具有相同扩展名的所有文件执行此操作。

4

2 回答 2

3

非交互式 shell 禁用了历史扩展。

将以下两行添加到您的脚本以启用它:

set -o history
set -o histexpand
于 2013-05-31T23:31:21.787 回答
1

(更新:我误解了原始问题是指脚本的参数,而不是脚本中当前命令的参数;这是一个重写的答案。)

正如@choroba 所说,默认情况下在脚本中禁用历史记录,因为在脚本中执行此类操作并不是真正的正确方法。

在脚本中执行此类操作的首选方法是将相关项目(在本例中为文件名)存储在变量中,然后在命令中多次引用它:

fname=file1
ls -l "$fname" > "/path/$fname.txt"

请注意,您几乎应该总是将变量引用放在双引号内(就像我在上面所做的那样)以避免它们包含空格或其他 shell 元字符时出现问题。如果要对多个文件执行此操作,请使用for循环:

for fname in *; do   # this will repeat for each file (or directory) in the current directory
    ls -l "$fname" > "/path/$fname.txt"
done

如果你想对当前目录以外的文件进行操作,事情会稍微复杂一些。您可以使用/inputpath/*,但它会包含每个文件名的路径(例如,它会使用“/inputpath/file1”、“/inputpath/file2”等运行循环),如果您直接在输出中使用它重定向你会得到类似的东西> /path/inputpath/file1.txt(即两个不同的路径将被附加在一起),可能不是你想要的。在这种情况下,您可以使用该basename命令去除不需要的路径以用于输出目的:

for fpath in /inputpath/*; do
    ls -l "$fpath" > "/path/$(basename "$fpath").txt"
done

如果您想要具有特定扩展名的文件列表,只需使用*.foo/inputpath/*.foo酌情。但是,在这种情况下,您最终会看到名为“file1.foo.txt”的文件的输出;如果您不想要堆叠扩展,basename也可以选择修剪它:

for fpath in /inputpath/*.foo; do
    ls -l "$fpath" > "/path/$(basename "$fpath" .foo).txt"
done

最后,将它包装在一个函数中可能会更简洁(取决于实际操作的复杂程度,以及它是否在脚本中多次出现),然后使用它:

doStuffWithFile() {
    ls -l "$1" > "/path/$(basename "$1" "$2").txt"
}

for fpath in /inputpath/*.foo; do
    doStuffWithFile "$fpath" ".foo"
done
doStuffWithFile /otherpath/otherfile.bar .bar
于 2013-05-31T23:20:58.950 回答