Bash命令在脚本中不起作用,但在控制台中

时间:2020-10-26 13:10:07

标签: bash

我已经在脚本中运行了两个命令,我想检查一下Directoy中的所有文件是否都是媒体:

1 All_LINES=$(ls -1 | wc -l)
2 echo "Number of lines: ${All_LINES}"
3
4 REACHED_LINES=$(ls -1 *(*.JPG|*.jpg|*.PNG|*.png|*.JPEG|*.jpeg) | wc -l)
5 echo "Number of reached lines: ${REACHED_LINES}"

if[...]

在外壳中按顺序运行第4行和第5行,按预期工作,计算以.jpg,.JPG ...结尾的所有文件。

在脚本中一起运行会产生以下错误:

Number of lines: 12
/home/andreas/.bash_scripts/rnimgs: command substitution: line 17: syntax error near unexpected token `('
/home/andreas/.bash_scripts/rnimgs: command substitution: line 17: `ls -1 *(*.JPG|*.jpg|*.PNG|*.png|*.JPEG|*.jpeg) | wc -l)'
Number of reached lines:

可以有人给我解释一下吗?

编辑:据我所知:

#!/bin/bash

# script to rename images, sorted by "type" and "date modified" and named by current folder

#get/set basename for files
CURRENT_BASENAME=$(basename "${PWD}")
echo -e "Current directory/basename is: ${CURRENT_BASENAME}\n"
read -e -p "Please enter basename: " -i "${CURRENT_BASENAME}" BASENAME
echo -e "\nNew basename is: ${BASENAME}\n"

#start
echo -e "START RENAMING"

#get nr of all files in directory
All_LINES=$(ls -1 | wc -l)
echo "Number of lines: ${All_LINES}"

#get nr of media files in directory
REACHED_LINES=$(ls -1 *(*.JPG|*.jpg|*.PNG|*.png|*.JPEG|*.jpeg) | wc -l)
echo "Number of reached lines: ${REACHED_LINES}"

EDIT1:再次感谢大家,这是我到目前为止的结果。仍有改进的空间,但可以开始测试。

#!/bin/bash

#script to rename media files to a choosable name (default: ${basename} of current directory) and sorted by date modified

#config
media_file_extensions="(*.JPG|*.jpg|*.PNG|*.png|*.JPEG|*.jpeg)"

#enable option extglob (extended globbing): If set, the extended pattern matching features described above under Pathname Expansion are enabled.
#more info: https://askubuntu.com/questions/889744/what-is-the-purpose-of-shopt-s-extglob
#used for regex
shopt -s extglob

#safe and set IFS (The Internal Field Separator): IFS is used for word splitting after expansion and to split lines into words with the read builtin command.
#more info: https://bash.cyberciti.biz/guide/$IFS
#used to get blanks in filenames
SAVEIFS=$IFS;
IFS=$(echo -en "\n\b");

#get and print current directory
basedir=$PWD
echo "Directory:" $basedir

#get and print nr of files in current directory
all_files=( "$basedir"/* )
echo "Number of files in directory: ${#all_files[@]}"

#get and print nr of media files in current directory
media_files=( "$basedir"/*${media_file_extensions} )
echo -e "Number of media files in directory: ${#media_files[@]}\n"

#validation if #all_files = #media_files
if [ ${#all_files[@]} -ne ${#media_files[@]} ]
then
  echo "ABORT - YOU DID NOT REACH ALL FILES, PLEASE CHECK YOUR FILE ENDINGS"
  exit
fi

#make a copy
backup_dir="backup_95f528fd438ef6fa5dd38808cdb10f"
backup_path="${basedir}/${backup_dir}"
mkdir "${backup_path}"
rsync -r "${basedir}/" "${backup_path}" --exclude "${backup_dir}"
echo "BACKUP MADE"

echo -e "START RENAMING"

#set new basename
basename=$(basename "${PWD}")
read -e -p "Please enter file basename: " -i "$basename" basename
echo -e "New basename is: ${basename}\n"

#variables
counter=1;
new_name="";
file_extension="";

#iterate over files
for f in $(ls -1 -t -r *${media_file_extensions})
do
  #catch file name
  echo "Current file is:           $f"
  #catch file extension
  file_extension="${f##*.}";
  echo "Current file extension is: ${file_extension}"
  #create new name
  new_name="${basename}_${counter}.${file_extension}"
  echo "New name is:               ${new_name}";
  #rename file
  mv $f "${new_name}";
  echo -e "Counter is:                ${counter}\n"

  ((counter++))
done

#get and print nr of media files before
echo "Number of media files before: ${#media_files[@]}"
#get and print nr of media files after
media_files=( "$basedir"/*${media_file_extensions} )
echo -e "Number of media files after: ${#media_files[@]}\n"

#delete backup?
while true; do
    read -p "Do you wish to keep the result? " yn
    case $yn in
        [Yy]* ) rm -r ${backup_path}; echo "BACKUP DELETED"; break ;;
        [Nn]* ) rm -r !(${backup_dir}); rsync -r "${backup_path}/" "${basedir}"; rm -r ${backup_path}; echo "BACKUP RESTORED THEN DELETED"; break;; 
        * ) echo "Please answer yes or no.";;
    esac
done

#reverse IFS to default
IFS=$SAVEIFS;

echo -e "END RENAMING"

3 个答案:

答案 0 :(得分:2)

正如@chepner在评论中指出的那样,您可能需要显式启用脚本的扩展glob。 c.f. Greg's WIKI

如果愿意,也可以压缩该模式以消除一些冗余并添加大小写混合-

$: ls -1 *.*([Jj][Pp]*([Ee])[Gg]|[Pp][Nn][Gg])
a.jpg
b.JPG
c.jpeg
d.JPEG
mixed.jPeG
mixed.pNg
x.png
y.PNG

您也可以不使用容易出错的ls来完成此操作。试试这个:

$: all_lines=(*)
$: echo ${#all_lines[@]}
55

$: reached_lines=( *.*([Jj][Pp]*([Ee])[Gg]|[Pp][Nn][Gg]) )
$: echo ${#reached_lines[@]}
8

c.f。 this breakdown

如果您只想计数,但不希望包含目录:

all_dirs=( */ )
num_files=$(( ${#all_files[@]} - ${#all_dirs[@]} ))

如果有机会创建一个名称与您的jpg / png模式匹配的目录,那么它将变得更加棘手。到那时,仅使用@ markp-fuso的解决方案可能会更容易。

最后一件事-避免使用全大写字母的变量名。这些通常保留给系统使用。

答案 1 :(得分:2)

您完全不需要在这里使用ls。参见https://mywiki.wooledge.org/ParsingLs

此外,请勿对您的私有变量使用大写字母。参见Correct Bash and shell script variable capitalization

#!/bin/bash

shopt -s extglob

read -e -p "Please enter basename: " -i "$PWD" basedir
all_files=( "$basedir"/* )
echo "Number of files: ${#all_files[@]}"

media_files=( "$basedir"/*(*.JPG|*.jpg|*.PNG|*.png|*.JPEG|*.jpeg) )
echo "Number of media files: ${#media_files[@]}"

答案 2 :(得分:0)

假设OP希望将计数限制为正常的文件(即,排除目录,管道,符号链接等非文件),则基于find的解决方案可以提供更准确的计数。

更新OP的原始代码以使用find(暂时忽略点文件):

ALL_LINES=$(find . -maxdepth 1 -type f | wc -l)
echo "Number of lines: ${ALL_LINES}"

REACHED_LINES=$(find . -maxdepth 1 -type f \( -iname '*.jpg' -o -iname '*.png' -o -iname '*.jpeg' \) | wc -l)
echo "Number of reached lines: ${REACHED_LINES}"
相关问题