Bash将字符串添加到文件名

时间:2017-08-21 14:27:53

标签: bash macos shell

我需要添加" hallo"在给定目录中的扩展名之前的每个文件名的末尾。但我的代码没有输出。 echo语句没有输出,文件名也没有改变

global $post;
$count = array(); // define $count as array variable
$args = array( 'post_type' => 'testimonial' 'posts_per_page' => -1, 'offset'=> 1);
$myposts = get_posts( $args );
foreach ( $myposts as $post ) : setup_postdata( $post ); 
   // push rating value inside the $count array
   $count[] = get_post_meta($post->ID, 'rating', true); 
endforeach; 
wp_reset_postdata();

$add = array_sum($count);  // You can use this variable outside also.
echo $add;  // print total rating.
echo $add/count($count) // Print average

2 个答案:

答案 0 :(得分:2)

使用bash,可以简化:

for f in *;do
echo "$f" "${f%.*}hallo.${f##*.}"
done

示例:

$ ls -all
-rw-r--r-- 1 29847 29847    0 Aug 21 14:33 file1.txt
-rw-r--r-- 1 29847 29847    0 Aug 21 14:33 file2.txt
-rw-r--r-- 1 29847 29847    0 Aug 21 14:33 file3.txt
-rw-r--r-- 1 29847 29847    0 Aug 21 14:33 file4.txt
-rw-r--r-- 1 29847 29847    0 Aug 21 14:33 file5.txt 

$ for f in *;do mv -v "$f" "${f%.*}hallo.${f##*.}";done
'file1.txt' -> 'file1hallo.txt'
'file2.txt' -> 'file2hallo.txt'
'file3.txt' -> 'file3hallo.txt'

$ ls -all
-rw-r--r-- 1 29847 29847    0 Aug 21 14:33 file1hallo.txt
-rw-r--r-- 1 29847 29847    0 Aug 21 14:33 file2hallo.txt
-rw-r--r-- 1 29847 29847    0 Aug 21 14:33 file3hallo.txt

这是有效的,因为${f%.*}返回没有扩展名的文件名 - 从末尾(向后)删除所有(*)到第一个/最短找到的点。

另一方面,这一个${f##*.}删除从开头到找到最长点的所有内容,只返回扩展名。

要克服注释中指出的无扩展文件问题,您可以执行以下操作:

$ for f in *;do [[ "${f%.*}" != "${f}" ]] && echo "$f" "${f%.*}hallo.${f##*.}" || echo "$f" "${f%.*}hallo"; done
file1.txt file1hallo.txt
file2.txt file2hallo.txt
file3.txt file3hallo.txt
file4 file4hallo
file5 file5hallo

如果文件没有扩展名,那么这将是真实的"${f%.*}" == "${f}"

答案 1 :(得分:1)

@GeorgeVasiliou已经展示了如何做你想做的事情;我将尝试解释原始脚本的错误。在许多地方,您使用了错误的语法来处理您尝试做的事情。

for file in $ls

这将扩展名为ls的shell变量,将其内容拆分为单词,将这些单词中找到的任何通配符展开为匹配文件列表,然后迭代结果。但是没有定义ls变量,所以它扩展为空,循环永远不会运行。我认为您正在尝试迭代ls命令的输出;其语法是for file in $(ls)。但是你不应该这样做,因为文件名可以包含空格和制表符,换行符和通配符以及各种其他有趣的字符,这些字符可以使迭代...除了文件名列表之外的其他内容。请参阅BashFAQ条目'Why you shouldn't parse the output of ls(1)'

您应该使用的是for file in **扩展为匹配文件列表(当前目录中的所有可见文件),然后该列表不会以任何方式混乱,只是直接迭代。唯一可能的问题是,如果没有任何匹配,则跳过扩展,并且循环运行一次,file设置为" *"。

echo $file

当使用一个没有双引号的变量时,它会经历上面描述的单词拆分和通配符扩展过程。通常,没有任何反应。有时会发生奇怪和意外的事情。使用双引号,例如echo "$file"

for f in $file

for ... in ...语句迭代单词,而不是字符。 shell没有特别好的方法来迭代字符串中的字符,但您可以使用for ((i=0; i<${#file}; i++)); do迭代字符数字,然后使用"${file:$i:1}"获取单个字符。

哦,for (( ))${var:start:length}构造是所有shell中都不可用的bash扩展。如果您想在脚本中使用其中一个或两个,请确保使用特定于bash的shebang行(#!/bin/bash#!/usr/bin/env bash)启动它。

if [ $f -eq $dot ];

同样,双引号变量引用以避免在变量包含空格或通配符时出现混乱,或者为空。此外,在[ ]测试中,-eq运算符执行数字比较而不是字符串比较;如果你给它不是有效数字的字符串,它会给出错误。对于字符串比较,请改用=。此外,在行的末尾不需要分号(好吧,除了case的末尾之外的一些地方)。如果then位于同一行,则您在此处使用分号,但如果它位于下一行,则不会使用分号。

count=$count+$f

此处的+将作为文字字符插入变量值中。要附加两个变量,只需使用count="$count$f"之类的内容。 (注意:这实际上是少数几个可以放弃双引号的地方之一。但我仍然建议使用它们,因为它很难跟踪它的位置。安全且不在哪里,所以总是双重引用你的变量要容易得多。)

mv $file $count

再次,双引号。此外,在运行任何类型的自动批量重命名/移动时,如果命名冲突(或错误),您应始终使用mv -nmv -i以防止覆盖文件或其他任何事情发生。

实际上,当我第一次运行这样的mass-mv脚本时,我喜欢在活动命令之前添加echo(例如echo mv -n "$file" "$count")所以我可以做一个在我删除echo并运行它之前,请确保它能够按照我的预期进行操作。