所以我有一些文件,其中包含要使用的内容和文件标题中的一些输入参数。我想更改输入但保持内容不变。我还根据正在使用的输入来命名文件。例如,假设我有一个文件名:
input1-input2-input3
我想复制该文件并将 input3 更改为 input4 或类似的内容,并且我希望名称能够反映这一点。我一直在尝试编写一个简单的 bash 脚本,如下所示:
#!/bin/bash
#Inputs:{file to be copied} {solvent to change}
file=${1?No file given}
input3=${2?no input}
做一些改变
cp file newfile
互联网给了我一些关于“做一些改变”的提示,比如这个提示: http://www.peteryu.ca/tutorials/shellscripting/batch_rename 所以我目前的尝试看起来像这样,文件名为
测试-gs-xcf-溶剂.gjf
#!/bin/bash
#Inputs:{file to be copied} {solvent to change}
file=${1?No file given}
solvent=${2?no solvent given}
filename=$(basename "$file" .gjf) ls -1 $file | awk '{print("mv "$1 "" $1)}' | sed "s/solvent/$solvent/2" > rename_"$filename".txt
newfile=awk '{print $3}' rename_"$filename".txt
if [ -f "$newfile" ]
then
echo "$newfile" > "$dir/newfile"
fi
cp "$file" "$newfile"
~
这对我来说不起作用,因为我认为该链接回答的是不同的问题。
总而言之,我有一个名为的文件:
input1-input2-input3
我想编写一个如下所示的 bash 脚本:
.\bash.bash input1-input2-input3 input4
输出为:
input1-input2-input4
理论上,我希望将来能够改变所有这些字段,但就目前而言,我只想让示例更简单一些。
谢谢大家!这是我在这里的第一篇文章,所以如果我有任何格式问题,请告诉我
答案1
你好,German Barcenas:)我们准备了一个小脚本,可以按照你在问题末尾的要求执行:
剧本
#!/bin/bash
# Get the input parameters
old_file=${1?No file given}
solvent=${2?no solvent given}
# Get the basename of the file
old_file_base=$(basename $old_file '.gjf')
# Run it through awk
new_file=$(echo $old_file_base | awk -v sol=$solvent '{split($0, tmp, "-"); \
tmp[3] = sol; print sprintf("%s-%s-%s", tmp[1], tmp[2], tmp[3])}')
# It can all be compressed into one line
# new_file=$(basename $old_file '.gjf' | awk -v sol=$solvent '{split($0, foo, "-"); \
# foo[3] = sol; print sprintf("%s-%s-%s", foo[1], foo[2], foo[3])}')
# Work with the file...
# Uncomment to check the new filename is correct
echo $new_file
# And copy the file
# cp $old_file $new_file
分解
我们已经尝试了该脚本bash 3.2.57
,它应该可以按原样运行。它只会输出将添加到新复制的文件的文件名,但您可以根据需要对其进行调整。让我们来看看每一部分。
- 输入参数
old_file=${1?No file given}
solvent=${2?no solvent given}
这部分是从您的示例中复制而来的,因此我们不会详细介绍。我们只想指出,我们更改了第一个输入参数的名称,以尝试使命名更清晰。
- 获取基本名称
old_file_base=$(basename $old_file '.gjf')
此部分将文件的基本名称保存到变量中old_file_base
。此额外步骤不是必需的,但我们已添加它以尝试使一切更清晰。我们运行此命令以使脚本工作,即使提供的文件路径是绝对路径(即,它是从根文件夹给出的,因此它以 开头/
。绝对路径的一个示例是/absolute/path/to/foo
)。
- 运行
awk
new_file=$(echo $old_file_base | awk -v sol=$solvent '{split($0, tmp, "-"); \
tmp[3] = sol; print sprintf("%s-%s-%s", tmp[1], tmp[2], tmp[3])}')
这就是程序的“核心”所在。我们首先使用 将echo
的内容输出old_file_name
到 STDOUT,然后使用管道 ( )将 的 STDOUT|
重定向到的 STDIN。这样将根据我们在上一步中获得的基本名称进行操作。echo
awk
awk
-v
请注意,我们在调用时使用了 option awk
。我们这样做是为了将外部变量“传递”给,以便awk
在处理输入时使用它们。我们可以在 within 中-v sol=$solvent
引用,其值将是脚本中变量的值(即运行脚本时传递的第二个参数)。然后我们在花括号之间找到“脚本”。它包含 3 条不同的指令:sol
awk
solvent
awk
A) split($0, tmp, "-")
:该split()
函数将获取整个输入($0
在内awk
)并将其按字符拆分-
。结果将返回到tmp
数组中。
b) tmp[3] = sol
:我们只需将其分配sol
给第三个元素。请注意,awk
索引从 1 开始,而不是从 0 开始!我们对索引进行硬编码,因为我们知道输入文件名的格式。否则,您可能需要在这里小心并手动检查数组的大小。
C) print sprintf("%s-%s-%s", tmp[1], tmp[2], tmp[3])
:该sprintf()
函数将“返回”我们通过将传递的值分配给用百分号 ( %
) 定义的占位符而获得的字符串。与 C 语言一样,%s
是字符串的占位符。在本例中,将返回由连字符 ( ) 连接的数组sprintf()
的三个元素作为字符串。由于我们之前用所需的输出更改了 的值,因此结果将是我们期望的结果。然后我们调用将该字符串输出到 STDOUT。由于整个命令都在命令替换结构(即)内,因此输出到 STDOUT 的内容将分配给变量。tmp
-
tmp[3]
print
$()
new_file
然后我们就得到了想要的输出!您可以通过运行echo $new_file
并检查终端的输出来检查。如果您在命令行上传递第三个参数来控制在文件名中要更改的输入,您可以直接awk
通过-v
选项将其传递给该参数,然后以您想要的方式处理该名称awk
。
示例输出
这些是我们在机器上得到的一些输出:
bash-3.2$ ./foo.sh input1-input2-input3 input-5
input1-input2-input-5
bash-3.2$ ./foo.sh input1-input2-input3 input-4
input1-input2-input-4
我们确实为我们的脚本命名了foo.sh
,但我们不太擅长起名字 :P
我希望这个脚本能帮到你。如果我误解了你的问题,或者你需要进一步的指导,请告诉我,这样我就可以提供帮助 :)