error handling considers everything an error - bash

I made a short script that changes all files with one extension to a different extension. Both extensions are inputted by the user through command line arguments. I put in an if statement to handle errors but for some reason it considers everything an error and I am not sure why. I have pasted the script below. I am rather new to bash scripting so any help would be greatly appreciated!
if [[ "$#" == 0 ]] || [[ "$1" || "$2" != "."* ]]
then
echo "Parameters are not valid"
exit
fi
for f in *"$1"; do
name=${f%.*}
mv $f "$name$2"
done

[[ "$1" || "$2" != "."* ]] should be [[ "$1" != .* ]] || [[ "$2" != .* ]]

Related

How to grep for multiple strings in the same line inside a file with similar pattern?

I have a file named my.txt:
abc_default_flow
#abc_default_flow -p sam
abc_default_flow -p sam
# abc_default_flow -p david
abc_default_flow -p david -z what_is_it
I want to match a particular line which has multiple strings and want to match the exact line which contains all the strings.
I tried the below piece of code, but as soon as it matches the partial string it comes out of the loop, rather than actual line which contains all the strings.
#!/bin/bash -f
f_name=abc_default_flow
p_name=sam
file_content=./my.txt
#echo "file_content: $file_content"
while IFS= read -r file_line
do
echo $file_line
if [[ $file_line != *"#"* ]] && [[ $file_line != "" ]] && echo $file_line | grep -E "${f_name}|${p_name}"; then
#if [[ $file_line != *"#"* ]] && [[ $file_line != "" ]] && echo $file_line | grep -v "${f_name}\|${p_name}"; then
#if [[ $file_line != *"#"* ]] && [[ $file_line != "" ]] && [[ $file_line =~ $f_name ]] && [[ $file_line =~ $p_name ]]; then
if [[ -z "$p_name" ]]; then
f_name=${f_name}_${p_name}
fi
echo "f_name: ${f_name}"
break
fi
done < $file_content
What would be the right way to grep or use any other process to find the right line within the file?
Update: With the below code I am able to get the output, but is there any simple way with grep or sed or awk to find the result in single line instead of nested if loops.
#!/bin/bash -f
f_name=abc_default_flow
p_name=david
file_content=./my.txt
echo "f_name: $f_name, p_name: $p_name"
while IFS= read -r file_line
do
if [[ $file_line != *"#"* ]] && [[ $file_line != "" ]]; then
echo "l1"
if [[ ! -z "$f_name" ]] && [[ $file_line =~ "$f_name" ]]; then
echo "l2, $file_line, $f_name, $p_name"
if [[ ! -z "$p_name" ]] && [[ $file_line =~ "$p_name" ]]; then
f_name=${f_name}_${p_name}
echo "f_name: ${f_name}"
break
elif [[ ! -z "$p_name" ]] && [[ ! $file_line =~ "$p_name" ]]; then
continue
else
break
fi
fi
fi
done < $file_content
You could use the same [[ ]] style checking for the two strings you're looking for:
if [[ $file_line != *"#"* ]] && [[ $file_line == *"$f_name"* ]] && [[ $file_line == *"$p_name"* ]]; then
...
fi
I removed the empty string check since an empty line won't contain $f_name and $p_name anyways.
If you expect sam will always come after abc_default_flow then you could combine the two checks into a single test:
if [[ $file_line != *"#"* ]] && [[ $file_line == *"$f_name"*"$p_name"* ]]; then
...
fi
If we look at the script as a whole, it'd be nice to get away from the explicit line-by-line loop. Scripts are more idiomatic when they chain together tools that process entire files. Something like:
sed -r '/^\s*#/d' my.txt | grep "$f_name" | grep "$p_name"

How can I call an external bash function with parameters in an if condition

I am trying to call an external bash script in an if condition in my main script.
The code of the external script IsArchive:
#!/bin/bash
STR="$1"
if [[ "$STR" == *".zip"* ]] || [[ "$STR" == *".iso"* ]] || [[ "$STR" == *".tar.gxz"* ]] || [[ "$STR" == *".tar.gx"* ]] || [[ "$STR" == *".tar.bz2"* ]] || \
[[ "$STR" == *".tar.gz"* ]] || [[ "$STR" == *".tar.xz"* ]] || [[ "$STR" == *".tgz"* ]] || [[ "$STR" == *".tbz2"* ]]
then
return 0
else
return 1
fi
and I try calling it in my main script as:
elif [[ $Option = "2" ]]
then
if IsArchive "$SourcePath";
then
less -1Ras "$SourcePath" | tee "$OutputFilePath"
#if file is not an archive
else
ls -1Rasl "$SourcePath" | tee "$OutputFilePath"
fi
when I execute the main script I receive the Error: ./script: line 61: IsArchive: command not found
You just need to make sure that the script is in your PATH. Either that, or reference it with either a full path or a relative path. Perhaps you just need to write:
if ./IsArchive "$SourcePath"; then ...
But there are several issues with IsArchive. You cannot return except from a function, so you probably want to use exit 0 and exit 1 instead of return. You probably don't want to consider a name like foo.zipadeedoodah to be an archive, but *".zip"* will match that, so you should probably remove the trailing *. It would be simpler to write it with a case statement:
#!/bin/bash
case "$1" in
*.zip|*.iso|*.tar.gxz|*.tar.gx|*.tar.bz2| \
*.tar.gz|*.tar.xz|*.tgz|*.tbz2) exit 0;;
*) exit 1;;
esac

BASH OR statement

I want to execute echo only if one of the folders are not found?
However AEM_SEGMENTSTORE_LOCATION_AZURE is found but I still get "echo not found"
#!/bin/bash
AEM_SEGMENTSTORE_LOCATION="/opt/day/${AEM_RUNMODE}/crx-quickstart/repository/segmentstore"
AEM_SEGMENTSTORE_LOCATION_AZURE="/opt/day/crx-quickstart/repository/segmentstore"
[[ ! -d ${AEM_SEGMENTSTORE_LOCATION} ]] || [[ ! -d ${AEM_SEGMENTSTORE_LOCATION_AZURE} ]] && echo "not found"
In general, don't mix || and &&. The precedence is not what you expect. a || b && c is equivalent to (a || b) && c, but a && b || c is not the same as (a && b) || c. Get in the habit of using a proper if statement.
if [[ ! -d "$AEM_SEGMENTSTORE_LOCATION" || ! -d "$AEM_SEGMENTSTORE_LOCATION_AZURE" ]]; then
echo "not found"
fi
or
if ! [[ -d "$AEM_SEGMENTSTORE_LOCATION" && -d "$AEM_SEGMENTSTORE_LOCATION_AZURE" ]]; then
echo "not found"
fi
The precedence is wrong. You seem to be looking for AND anyway. You can easily fix this by changing it to
if [[ ! -d "$AEM_SEGMENTSTORE_LOCATION" ]] &&
[[ ! -d "$AEM_SEGMENTSTORE_LOCATION_AZURE" ]]
then
echo "$0: not found" >&2
fi
Notice also proper quoting of your variables {see When to wrap quotes around a shell variable; braces do not quote, and were basically useless here) and probably avoid uppercase variable names if these are private variables of yours (uppercase is reserved for system variables). Finally, the diagnostic message should probably go to standard error, and include the script's name; it should probably also say what was not found.

check if file has an appropriate suffix bash

FileI wrote this
function copyFile() {
local source=$1
set -x
for dictionary in $DICT_PATH; do
dictname=$(basename $dictionary)
dict_prefix=${dictname%%.*}
TARGET="gs://bucket/files"
gsutil cp -r $dictionary $TARGET
done
}
I want to add a condition to copy only files whose termination is .json or .xml
I wrote this
function copyFile() {
local source=$1
set -x
for dictionary in $DICT_PATH; do
dictname=$(basename $dictionary)
if [[ ${dictname: -5} == ".json" ]] || [[ ${dictname: -5} == ".xml" ]] ; then
dict_prefix=${dictname%%.*}
TARGET="gs://bucket/files"
gsutil cp -r $dictionary $TARGET
fi
done
}
but this didn't work. Any idea how to fix this please.
xml is a shorter string than json, so your suffix is too long to compare equal to .xml.
# -4, not -5
if [[ ${dictname: -5} == ".json" ]] || [[ ${dictname: -4} == ".xml" ]] ; then
You can avoid this mistake by using the much simpler pattern-matching facilities of [[ ... ]].
if [[ $dictname = *.json || $dictname = *.xml ]]; then
or even a POSIX-compatible case statement:
case $dictname in
*.json|*.xml)
dict_prefix=${dictname%%.*}
TARGET="gs://bucket/files"
gsutil cp -r "$dictionary" "$TARGET"
;;
sac
You can extract the file extension as ${filename#*.}.
This should give something like following,
ext=${dictname#*.}
if [[ $ext == 'json']] || [[ $ext == 'xml' ]]; then
# code
fi
Or, use regular expressions,
if [[ $dictname =~ (json|xml)$ ]]; then
# code
fi
Try this:
filetype=${dictionary##*.}
if [[ "$filetype" == "json" ]] || [[ "$filetype" == "xml" ]]; then
echo YES
fi

bash: check if two variables both do or do not exist (aka comparing results of comparisons)

I am writing a bash script that sometimes will use environment variables GIT_DIR and GIT_WORK_TREE. The bash script can only operate correctly if either both variables exist or neither exist. In case there's a technical difference, it makes no difference
This works, but there has to be a better way:
if [[ -z "${GIT_DIR}" ]]; then
_GIT_DIR_EXISTS=0
else
_GIT_DIR_EXISTS=1
fi
if [[ -z "${GIT_WORK_TREE}" ]]; then
_GIT_WORK_TREE_EXISTS=0
else
_GIT_WORK_TREE_EXISTS=1
fi
if [[ "${_GIT_DIR_EXISTS}" -ne "${_GIT_WORK_TREE_EXISTS}" ]]; then
echo "GIT_DIR is ${GIT_DIR}"
echo "GIT_WORK_TREE is ${GIT_WORK_TREE}"
echo "Both or none must exist"
exit 1
fi
I tried:
if [[ (-z "${GIT_DIR}") -ne (-z "${GIT_WORK_TREE}") ]]; then
But that gives this error:
bash: syntax error in conditional expression
bash: syntax error near '-ne'
I then resorted to trying semi-random things, with varying errors:
if [[ -z "${GIT_DIR}" -ne -z "${GIT_WORK_TREE}" ]]; then
if [[ [-z "${GIT_DIR}"] -ne [-z "${GIT_WORK_TREE}"] ]]; then
if [[ [[-z "${GIT_DIR}"]] -ne [[-z "${GIT_WORK_TREE}"]] ]]; then
if [[ -z "${GIT_DIR}" ]] ^ [[ -z "${GIT_WORK_TREE}" ]]; then
if { [[ -z "${GIT_DIR}" ]] } -ne { [[ -z "${GIT_WORK_TREE}" ]] }; then
if [[ (( -z "${GIT_DIR}" )) -ne (( -z "${GIT_WORK_TREE}" )) ]]; then
I tried:
if [[ $(test -z "${GIT_DIR}") -ne $(test -z "${GIT_WORK_TREE}") ]]; then
But realized that doesn't work because it's a sub-process, and they'd need to be exported. as Socowl comments, this compares the outputs of the test commands which output nothing, not their exit statuses.
I apologize if this is a duplicate. I've searched here and google for a while, and must not be using the right terminology.
How about this:
if [[ "${GIT_DIR:+set}" != "${GIT_WORK_TREE:+set}" ]]; then
echo "GIT_DIR is '${GIT_DIR}'"
echo "GIT_WORK_TREE is '${GIT_WORK_TREE}'"
echo "Both or none must exist"
exit 1
fi
Explanation: ${var:+value} is a variant of parameter expansion that gives "value" if var is set to a nonempty string, or the empty string if var is unset or empty. So if both vars are unset/empty, it becomes if [[ "" != "" ]]; then, and if they're both set it becomes if [[ "set" != "set" ]]; then etc.
BTW, if you want to test whether the variables are set at all (even if to the empty string), use ${var+value} (note the lack of colon). The bash manual lists the :+ version, but not the + version.

Resources