简体   繁体   English

如何根据bash脚本中的命令行参数命名输出文件?

[英]How to name output file according to a command line argument in a bash script?

These lines work when copy-pasted to the shell but don't work in a script: 这些行在复制粘贴到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

What's the syntax for doing this in a bash script? 在bash脚本中执行此操作的语法是什么?

If possible, I would like to know how to do this for one file and for all files with the same extension in a folder. 如果可能,我想知道如何对一个文件以及文件夹中具有相同扩展名的所有文件执行此操作。

Non-interactive shell has history expansion disabled. 非交互式外壳已禁用历史记录扩展。

Add the following two lines to your script to enable it: 将以下两行添加到脚本中以启用它:

set -o history
set -o histexpand

(UPDATE: I misunderstood the original question as referring to arguments to the script, not arguments to the current command within the script; this is a rewritten answer.) (更新:我误解了原始问题,是指脚本的参数,而不是脚本中当前命令的参数;这是一个重写的答案。)

As @choroba said, history is disabled by default in scripts, because it's not really the right way to do things like this in a script. 正如@choroba所说,默认情况下,脚本中的历史记录是禁用的,因为这不是在脚本中执行此类操作的正确方法。

The preferred way to do things like this in a script is to store the item in question (in this case the filename) in a variable, then refer to it multiple times in the command: 在脚本中执行此类操作的首选方法是将有问题的项(在本例中为文件名)存储在变量中,然后在命令中多次引用该项:

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

Note that you should almost always put variable references inside double-quotes (as I did above) to avoid trouble if they contain spaces or other shell metacharacters. 请注意,您几乎应该始终将变量引用放在双引号中(如我上面所做的那样),以避免在它们包含空格或其他shell元字符的情况下出现麻烦。 If you want to do this for multiple files, use a for loop: 如果要对多个文件执行此操作,请使用for循环:

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

If you want to operate on files someplace other than the current directory, things are a little more complicated. 如果要对当前目录以外的其他位置的文件进行操作,则情况会有些复杂。 You can use /inputpath/* , but it'll include the path along with each filename (eg it'd run the loop with "/inputpath/file1", "/inputpath/file2", etc), and if you use that directly in the output redirect you'll get something like > /path/inputpath/file1.txt (ie the two different paths will get appended together), probably not what you want. 您可以使用/inputpath/* ,但是它将包含路径以及每个文件名(例如,它将使用“ / inputpath / file1”,“ / inputpath / file2”等运行循环),如果使用的话直接在输出重定向中,您会得到类似> /path/inputpath/file1.txt (即,两个不同的路径将被附加在一起),可能不是您想要的。 In this case, you can use the basename command to strip off the unwanted path for output purposes: 在这种情况下,可以使用basename命令剥离不必要的路径以用于输出:

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

If you want a list of files with a particular extension, just use *.foo or /inputpath/*.foo as appropriate. 如果要使用具有特定扩展名的文件列表,只需适当地使用*.foo/inputpath/*.foo However, in this case you'll wind up with the output going to files named eg "file1.foo.txt"; 但是,在这种情况下,您将输出到名为“ file1.foo.txt”的文件; if you don't want stacked extensions, basename has an option to trim that as well: 如果您不希望堆叠扩展名, basename也可以对其进行修剪:

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

Finally, it might be neater (depending how complex the actual operation is, and whether it occurs multiple times in the script) to wrap this in a function, then use that: 最后,将其包装到函数中,然后使用它可能会更整洁(取决于实际操作的复杂程度以及它是否在脚本中多次出现)。

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

for fpath in /inputpath/*.foo; do
    doStuffWithFile "$fpath" ".foo"
done
doStuffWithFile /otherpath/otherfile.bar .bar

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM