Unix & Linux Stack Exchange
Q&A for users of Linux, FreeBSD and other Unix-like operating systems
Latest Questions
220
votes
8
answers
44353
views
Why is looping over find's output bad practice?
This question is inspired by [_Why is using a shell loop to process text considered bad practice ?_][1] I see these constructs for file in `find . -type f -name ...`; do smth with ${file}; done and for dir in $(find . -type d -name ...); do smth with ${dir}; done being used here almost on a daily ba...
This question is inspired by
_Why is using a shell loop to process text considered bad practice ?_
I see these constructs
for file in
find . -type f -name ...
; do smth with ${file}; done
and
for dir in $(find . -type d -name ...); do smth with ${dir}; done
being used here almost on a daily basis even if some people take the time to comment on those posts explaining why this kind of stuff should be avoided...
Seeing the number of such posts (and the fact that sometimes those comments are simply ignored) I thought I might as well ask a question:
*Why is looping over find
's output bad practice and what's the proper way to run one or more commands for each file name/path returned by find
?*
don_crissti
(85483 rep)
Nov 7, 2016, 06:22 PM
• Last activity: Apr 19, 2025, 09:44 AM
0
votes
1
answers
85
views
How to batch compress pdfs?
I'm looking to batch compress some pdfs, using the convert to/from ps trick outlined elsewhere. I have a function defined in an .zshrc file: ``` function pdfcompress() { for f in "$1"; do echo "compressing $1" pdf2ps "$f" "$f".ps ps2pdf -dPDFSETTINGS=/default "$f".ps "$f" rm "$f".ps done } ``` My un...
I'm looking to batch compress some pdfs, using the convert to/from ps trick outlined elsewhere. I have a function defined in an .zshrc file:
function pdfcompress() {
for f in "$1"; do
echo "compressing $1"
pdf2ps "$f" "$f".ps
ps2pdf -dPDFSETTINGS=/default "$f".ps "$f"
rm "$f".ps
done
}
My understanding is that I should be able to pass this a list of pdfs, and it compresses them. However, the following happens:
% ls | pdfcompress
compressing
Error: /undefinedfilename in --findlibfile--
Operand stack:
()
Execution stack:
%interp_exit .runexec2 --nostringval-- findlibfile --nostringval-- 2 %stopped_push --nostringval-- findlibfile
findlibfile false 1 %stopped_push findlibfile 1815 1 3 %oparray_pop findlibfile
Dictionary stack:
--dict:743/1123(ro)(G)-- --dict:0/20(G)-- --dict:85/200(L)--
Current allocation mode is local
GPL Ghostscript 10.04.0: Unrecoverable error, exit code 1
GPL Ghostscript 10.04.0: Device 'pdfwrite' requires an output file but no file was specified.
**** Unable to open the initial device, quitting.
It seems that none of the file names are getting passed, for some reason. I've also tried approaches with find . -iname "*.pdf" -exec pdfcompress
, and piping to xargs pdfcompress
, but neither of those work because the function isn't in the environment. Other times the placeholder variables seem to be interpreted as literal strings.
I've been trying to get this to work in some form for over an hour with no luck. Any tips?
I have a folder structure of pdfs that I would like to maintain, so a solution that works recursively within directories would be best, if possible.
Thank you!
sporkl
(103 rep)
Feb 21, 2025, 08:26 PM
• Last activity: Feb 22, 2025, 06:13 PM
0
votes
1
answers
38
views
terraform resource dependency with count(loop)
I'm trying to create stack of multiple vms on KVM_HOST with terraform. The catch is, I'm using pxeboot & kickstart to do installation. Kickstart file needs to carry some dynamic information, like static IPs, hostname etc, therefore I have to create it for each vm, and this kickstart file needs to st...
I'm trying to create stack of multiple vms on KVM_HOST with terraform. The catch is, I'm using pxeboot & kickstart to do installation. Kickstart file needs to carry some dynamic information, like static IPs, hostname etc, therefore I have to create it for each vm, and this kickstart file needs to stay there till vm reads it & starts installation. Then next kickstart file is created for vm 2, and it needs to stay there till vm2 reads it for installation. So there should be some delay in creating these resources, either with loop or depend_on parameter, but what I'm getting is, kickstart files for all vms are generated right away, last one is overriding, of course, so correct info is not passed.
here's two resources which I need to loop in sequence for number of variable value qty
variable "vm_count" {
type = number
default = 1
}
below are resources
resource "null_resource" "delay" {
count = var.vm_count
provisioner "local-exec" {
command = "sleep 150"
}
depends_on = [libvirt_domain.vm]
}
resource "local_file" "kickstart_file" {
count = var.vm_count
content = templatefile("ks.tpl", {
ip = "192.168.1.${117 + count.index}"
netmask = var.netmask
gateway = var.gateway
dns = var.dns
hostname = "${var.hostname}-${count.index + 1}"
disk_size_rounded = ((var.disk_size - 1) * 1024) -1
})
filename = "/var/www/html/kickstart/ks-terraform.cfg"
}
resource "libvirt_domain" "vm" {
count = var.vm_count
name = "${var.hostname}-${count.index + 1}"
memory = var.memory
vcpu = var.cpu
arch = "x86_64"
cpu {
mode = "host-passthrough"
}
boot_device {
dev = ["hd", "network"]
}
disk {
volume_id = libvirt_volume.default_disk[count.index].id
}
graphics {
type = "vnc"
listen_type = "address"
autoport = true
}
network_interface {
bridge = "virbr0"
macvtap = false
}
depends_on = [local_file.kickstart_file, null_resource.delay]
}
how can I improve the logic with depends on or for_each?
Sollosa
(1993 rep)
Feb 11, 2025, 02:11 PM
• Last activity: Feb 11, 2025, 07:18 PM
0
votes
2
answers
1678
views
for loop in FreeBSD (pfSense) doesn't work
I've just noticed that the same code for `for loop` in bash doesn't work in FreeBSD wolf@linux:~$ echo $SHELL /bin/bash wolf@linux:~$ wolf@linux:~$ for i in {1..3}; do echo $i; done 1 2 3 wolf@linux:~$ Is there any alternative for this? [2.5.0-RELEASE][admin@pfSense]/root: echo $SHELL /etc/rc.initia...
I've just noticed that the same code for
for loop
in bash doesn't work in FreeBSD
wolf@linux:~$ echo $SHELL
/bin/bash
wolf@linux:~$
wolf@linux:~$ for i in {1..3}; do echo $i; done
1
2
3
wolf@linux:~$
Is there any alternative for this?
[2.5.0-RELEASE][admin@pfSense]/root: echo $SHELL
/etc/rc.initial
[2.5.0-RELEASE][admin@pfSense]/root:
[2.5.0-RELEASE][admin@pfSense]/root: for i in {1..3}; do echo $i; done
for: Command not found.
i: Undefined variable.
[2.5.0-RELEASE][admin@pfSense]/root:
Wolf
(1741 rep)
Mar 7, 2021, 12:11 PM
• Last activity: Oct 17, 2024, 05:05 AM
3
votes
2
answers
1841
views
How to extract and delete contents of a zip archive simultaneously?
I want to download and extract a large zip archive (>180 GB) containing multiple small files of a single file format onto an SSD, but I don't have enough storage for both the zip archive and the extracted contents. I know that it would be possible to extract and delete individual files from an archi...
I want to download and extract a large zip archive (>180 GB) containing multiple small files of a single file format onto an SSD, but I don't have enough storage for both the zip archive and the extracted contents. I know that it would be possible to extract and delete individual files from an archive using the zip command as mentioned in the answers [here](https://unix.stackexchange.com/questions/14120/extract-only-a-specific-file-from-a-zipped-archive-to-a-given-directory) and [here](https://superuser.com/questions/600385/remove-single-file-from-zip-archive-on-linux) . I could also get the names of all the files in an archive using the
-l
command, store the results in an array as mentioned [here](https://www.baeldung.com/linux/reading-output-into-array) , filter out the unnecessary values using the method given [here](https://stackoverflow.com/questions/9762413/bash-array-leave-elements-containing-string) , and iterate over them in BASH as mentioned [here](https://www.cyberciti.biz/faq/bash-for-loop-array/) . So, the final logic would look something like this:
1. List the zip file's contents using -l
and store the filenames in a bash array, using regular expressions to match the single file extension present in the archive.
2. Iterate over the array of filenames and successively extract and delete individual files using the -j -d
and -d
commands.
How feasible is this method in terms of time required, logic complexity, and computational resources? I am worried about the efficiency of deleting and extracting single files, especially with such a large archive. If you have any feedback or comments about this approach, I would love to hear them. Thank you all in advance for your help.
**Edit 1:**
It seems this question has become a bit popular. Just in case anyone is interested, here is a BASH script following the logic I have outlined earlier, with batching for the extraction and deletion of files to reduce the number of operations. I have used DICOM files in this example but this would work for any other file type or for any files whose file names can be described by a regular expression. Here is the code:
#!/bin/bash
# Check if a zip file is provided as an argument
if [ -z "$1" ]; then
echo "Usage: $0 "
exit 1
fi
zipfile=$1
# List the contents of the zip file and store .dcm files in an array
mapfile -t dcm_files < <(unzip -Z1 "$zipfile" | grep '\.dcm$')
# Define the batch size
batch_size=10000
total_files=${#dcm_files[@]}
# Process files in batches
for ((i=0; i
The file would have to be saved with a name like .sh
with a .sh
extension and marked as executable. If the script and archive are in the same folder and the name of the archive is .zip
, the method to run the script would be ./inplace_extractor.sh archive.zip
. Feel free to adjust the batch size or the regular expression or account for any subfolders in your archive.
I tried it with my large archive and the performance was absolutely abysmal while the disk space rapidly shrunk, so I would still recommend going with the approaches suggested in other answers.
Kumaresh Balaji Sundararajan
(51 rep)
Nov 12, 2023, 12:24 PM
• Last activity: Oct 5, 2024, 11:37 AM
6
votes
2
answers
7547
views
How to exit a bash loop by keyboard input?
I have a `bash lopp` as #!/bin/bash for (( c=0; c<=1000000; c++ )) do SOME STUFF HERE done I interrupt the long loop by a keyboard input like `Ctrl+C` but `Ctrl+C` simply terminates the script. I am looking for an alternative to continue the current cycle and break the loop after finishing the runni...
I have a
bash lopp
as
#!/bin/bash
for (( c=0; c<=1000000; c++ ))
do
SOME STUFF HERE
done
I interrupt the long loop by a keyboard input like Ctrl+C
but Ctrl+C
simply terminates the script. I am looking for an alternative to continue the current cycle and break the loop after finishing the running STUFF
in the current cycle.
Googlebot
(2009 rep)
Apr 27, 2017, 10:25 PM
• Last activity: Jul 26, 2024, 02:12 PM
2
votes
1
answers
166
views
Not working break in for loop in bash script for mounting a VHD
I'm not an experienced programmer. So maybe it's obvious for you why the break command in this script does not terminate the loop, but I can't see what is causing the problem. I want to use the script to mount a VHD file to the first empty NBD "slot" (which is assumed when it's size is zero, I took...
I'm not an experienced programmer. So maybe it's obvious for you why the break command in this script does not terminate the loop, but I can't see what is causing the problem. I want to use the script to mount a VHD file to the first empty NBD "slot" (which is assumed when it's size is zero, I took this idea from another thread on this site).
function vhdmount() {
workfile="$1"
if test -e "$workfile"
then
workname=${workfile##*'/'}
echo "$(tput setaf 3)*** ${workfile}: ***$(tput setaf 7)"
for (( i=0; i<16; i++ ))
do (
if test -e /sys/class/block/nbd${i}/size
then
usedornot=$( cat /sys/class/block/nbd${i}/size )
if (( "$usedornot" == 0 ))
then
firstfree=$i
break
fi
else
firstfree=$i
break
fi
); done
sudo modprobe nbd
sudo qemu-nbd -c /dev/nbd${firstfree} "$workfile"
sudo mkdir "/media/myusername/${workname//.vhd/.nbd${firstfree}}/"
sudo mount /dev/nbd${firstfree}p1 "/media/myusername/${workname//.vhd/.nbd${firstfree}}/"
echo "$(tput setaf 3) successfully mounted.$(tput setaf 7)"
fi
}
vhdmount "$1"
Maybe there are other errors as well. I'm always terminating the shell when it asks for the password, because I can tell from the 16 messages telling me that a break command is only useful in a for loop that the break command did not work. By the way, what a useless error message is that?!
Shakesbeer
(123 rep)
Jun 24, 2024, 10:03 AM
• Last activity: Jun 24, 2024, 10:32 AM
0
votes
1
answers
59
views
using a variable which has content separated by spaces in shell in a for loop
I am trying to read a variable with spaces on prompt and trying to use in a for loop., For example: ```none Enter the items to read separated by space... apple orange kiwi ``` ```sh read items for i in "$items" do echo $i ...(additional operations).... done ``` But shell does take the first item - a...
I am trying to read a variable with spaces on prompt and trying to use in a for loop.,
For example:
Enter the items to read separated by space...
apple orange kiwi
read items
for i in "$items"
do
echo $i
...(additional operations)....
done
But shell does take the first item - apple here. What am I missing here.
sabarish tr
(1 rep)
May 8, 2024, 09:27 PM
• Last activity: May 8, 2024, 11:06 PM
-1
votes
1
answers
73
views
Output of loop variable shows different value than expected
Imagine I have two folders in my current working directory: `back/` and `front/`. I am trying to enter inside each of them and do some stuff. From the simple script below: ```lang-shell for dir in */ ; do echo "$(dir)" done ``` I was expecting an output like: ```none back front ``` However, what I a...
Imagine I have two folders in my current working directory:
back/
and front/
. I am trying to enter inside each of them and do some stuff. From the simple script below:
-shell
for dir in */ ; do
echo "$(dir)"
done
I was expecting an output like:
back
front
However, what I am getting is:
back front
back front
I don't understand. The consequence is that, if I try to cd
into the folder:
-shell
for dir in */ ; do
echo "$(dir)"
cd $(dir)
echo "$(pwd)"
cd ..
done
I get:
back front
/path/to/back
back front
/path/to/back
I.e. I never enter front/
. Could someone please help me understand what I am doing wrong?
Rigel F. do C.
(1 rep)
Apr 22, 2024, 03:06 PM
• Last activity: Apr 24, 2024, 12:50 PM
-3
votes
4
answers
191
views
How to catch all lines of a repeating pattern and do some actions with the subresults
I am looking for a possibility to catch in a repeating text pattern all variable amount of lines between them and then do an action with it in bash. Example text: ``` Total: text1 text2 Total: text3 Total: Text1 Text4 Text5 ``` What I am aiming to do is basically a for loop over the matches with `To...
I am looking for a possibility to catch in a repeating text pattern all variable amount of lines between them and then do an action with it in bash.
Example text:
Total:
text1
text2
Total:
text3
Total:
Text1
Text4
Text5
What I am aiming to do is basically a for loop over the matches with Total:
and then do an action with it, which is always going to be the first section of the follow-up subtext.
Something like in high level language:
for (cat filename = every "Total:" do end
Now the interesting part for me is basically how to organize that for loop?
In the ` part I want do some
jq and
awk`.
The results would be basically based on the example text these three matches:
1.
Total:
text1
text2
2.
Total:
text3
3.
Total:
Text1
Text4
Text5
Hope the last description describes it.
What could be the right tool for catching this? Would that be rather a combination of for
and grep
or for
and awk
?
I would like to use no more than GNU tools. So no perl
or other external tools.
Thanks a lot.
André Letterer
(9 rep)
Apr 2, 2024, 04:01 PM
• Last activity: Apr 3, 2024, 12:34 PM
4
votes
2
answers
460
views
SSH for loop: parameter passed to function captured in variable is not expanded
I have several servers which have several files with deploy date info I need to parse, and get a local copy of the files which are 2 months old or older. ```bash #!/bin/bash # split on new line not space # don't want to quote everything # globbing desired IFS=$'\n' servers=( blue red ) parseDate() {...
I have several servers which have several files with deploy date info I need to parse, and get a local copy of the files which are 2 months old or older.
#!/bin/bash
# split on new line not space
# don't want to quote everything
# globbing desired
IFS=$'\n'
servers=(
blue
red
)
parseDate() {
grep 'deploy_date:' $file | \
sed ... | \
# much more in here...
}
getOldFiles() {
local #all vars
currentDateInSecs=$(date +%s)
twoMonthsInSecs=526000
for server in ${servers[@]}; do
oldfile=$(
ssh $server "
$(declare -f parseDate)
for file in /dir/$server/file*; do
dateInSecs=$(date -jf '%b/%e/%Y' $(parseDate) +%s)
timeDiff=$((\$currentDateInSecs - \$dateInSecs))
((\$timeDiff >= \$twoMonthsInSecs)) &&
cat \$file
done
"
)
[ -n $oldFile ] &&
cat $oldFile ~/oldFiles/${server}-${file}.txt
done
### Problem:
Current issue is with dateInSecs=$(date -jf '%b/%e/%Y' $(parseDate \$file) +%s)
.
When parseDate \$file
is in $()
the $file
variable is not expanded, it works fine without command substitution, but I need it.
How do I fix this?
### Info:
This isn't a script, they're in my ~/.bash_profile
This is a script (among other scripts) in a git repo which is sourced from ~/bash_profile
(I have an install script which sets sources using $PWD
) so people can use these commands directly instead of cd'ing to the git repo (which has many other things not applicable to the them).
Runs from Macos to CentOS servers.
Nickotine
(554 rep)
Jan 30, 2024, 05:26 PM
• Last activity: Feb 2, 2024, 05:33 PM
0
votes
2
answers
322
views
How to run for loop over SSH on remote so that variables expand?
If I `ls` files without a for loop in a remote host everything is fine however, if I capture the `ls` in a variable and try to `echo` each file it fails as the variables don't expand/have a value. What I mean: ```bash IFS=$'\n' servers=( blue green red ) ``` ```bash for i in ${servers[@]}; do ssh $i...
If I
ls
files without a for loop in a remote host everything is fine however, if I capture the ls
in a variable and try to echo
each file it fails as the variables don't expand/have a value.
What I mean:
IFS=$'\n'
servers=(
blue
green
red
)
for i in ${servers[@]}; do
ssh $i "
ls /dir/xyz_${i}*/details.txt
"
done
/dir/xyx_blue0/details.txt
/dir/xyz_blue1/details.txt
/dir/xyx_green2/details.txt
/dir/xyz_green4/details.txt
/dir/xyx_red1/details.txt
/dir/xyz_red8/details.txt
But I actually need to loop through the output of ls
so I can do things to the files, however the variable doesn't expand:
for i in ${servers[@]}; do
ssh $i "
for i in $(ls /dir/xyz_${i}*/details.txt); do
echo $i
done
"
done
not found: /dir/xyx_blue*/details.txt
not found: /dir/xyx_green*/details.txt
not found: /dir/xyx_red*/details.txt
How can I get $i
to expand when running a loop on the remote host?
Nickotine
(554 rep)
Jan 29, 2024, 11:48 PM
• Last activity: Jan 31, 2024, 02:04 PM
0
votes
2
answers
2459
views
Shell script with a for loop and an “array”
How can I use this shell script with for loop and an array. I would like to call create condition for quality gate creation of sonarqube with a for loop. Example: ``` #!/bin/bash --login echo "Creating SonarQube Gateway Condition" QG_ID=$(cat qualitygate.json | jq -r ".id") Gateway="curl -u ${USERNA...
How can I use this shell script with for loop and an array.
I would like to call create condition for quality gate creation of sonarqube with a for loop. Example:
#!/bin/bash --login
echo "Creating SonarQube Gateway Condition"
QG_ID=$(cat qualitygate.json | jq -r ".id")
Gateway="curl -u ${USERNAME}:${PASSWORD} -k -X POST "${SONAR_HOST_URL}/api/qualitygates/create_condition?"
declare -a gateMetrics=("gateId=$QG_ID&metric=coverage&op=LT&error=80\"" "gateId=$QG_ID&metric=duplicated_lines_density&op=GT&error=10\"")
for val in "${gateMetrics[@]}"
do
echo $Gateway$val
done
I want the output as below after running above command
curl -u ${USERNAME}:${PASSWORD} -k -X POST "${SONAR_HOST_URL}/api/qualitygates/create_condition?gateId=$QG_ID&metric=coverage&op=LT&error=80"
user1628
(11 rep)
Jan 25, 2021, 08:09 AM
• Last activity: Dec 17, 2023, 07:03 AM
0
votes
2
answers
297
views
Pass multiple arguments from single line from a text file to teminal
I have a python program that requires 2 arguments input-file and output-file. It reads input-file and creates a copy of that file with some modifications in the output-file. I created a text file with a set of arguments. It has multiple sets of arguments on multiple lines. But for 1 execution of a p...
I have a python program that requires 2 arguments input-file and output-file.
It reads input-file and creates a copy of that file with some modifications in the output-file.
I created a text file with a set of arguments. It has multiple sets of arguments on multiple lines. But for 1 execution of a program it needs to read line by line. So each line has 2 args (separated by a space) to be passed: input-file and output-file.
Example of file with arguments (call it *File-With-Multiple-Arguments-Per-Line.txt*):
input-file-1-path/input-file-1-name.sql output-file-1-path/output-file-1-name.sql
input-file-2-path/input-file-2-name.sql output-file-2-path/output-file-2-name.sql
input-file-3-path/input-file-3-name.sql output-file-3-path/output-file-3-name.sql
input-file-4-path/input-file-4-name.sql output-file-4-path/output-file-4-name.sql
I tried this:
for arg in $(`
But using
"$arg" "$arg"
leads to incorrect interpretation of my program. As if does the same task 3 times - first time does what is intended; second time using input-file as output and input; third time using output-file as output and input.
I've tried the solution below as well, but then my program does not do anything. Though it displays the output in my terminal as if it did what was supposed to be done. And no error appears.
For reference: https://unix.stackexchange.com/questions/429834/reading-multiple-arguments-for-a-shell-script-from-file
while read x y; do
python /Users/Git-Repos/MyProgram.py "$x" "$y"
done < /Users/Repository/File-With-Multiple-Arguments-Per-Line.txt
Data Engineer
(113 rep)
Nov 3, 2023, 12:15 AM
• Last activity: Nov 3, 2023, 04:55 PM
1
votes
1
answers
1591
views
csh: redirecting output from foreach
In csh: How do I redirect the output from a `foreach`-loop to a pipe? This works but uses a temp file: set tmpfile=/tmp/file true > $tmpfile foreach v (`set | awk -e '{print $1}' |grep -v prompt2`); eval if'($?'$v' && ${#'$v'} > $tmpfile eval if'($?'$v' && ${#'$v'} > 1) echo array'$v'="$'$v'"' >> $t...
In csh: How do I redirect the output from a
foreach
-loop to a pipe?
This works but uses a temp file:
set tmpfile=/tmp/file
true > $tmpfile
foreach v (set | awk -e '{print $1}' |grep -v prompt2
);
eval if'($?'$v' && ${#'$v'} > $tmpfile
eval if'($?'$v' && ${#'$v'} > 1) echo array'$v'="$'$v'"' >> $tmpfile
end
cat $tmpfile | parallel --shellquote | perl -pe 's/^scalar(\S+).=/set $1=/ or s/^array(\S+).=(.*)/set $1=($2)/;'
I would like to get rid of the temp file and use a pipe instead. So something like this (does not work):
( foreach v (set | awk -e '{print $1}' |grep -v prompt2
);
eval if'($?'$v' && ${#'$v'} 1) echo array'$v'="$'$v'"'
end ) | parallel --shellquote | perl -pe 's/^scalar(\S+).=/set $1=/ or s/^array(\S+).=(.*)/set $1=($2)/;'
Ole Tange
(37348 rep)
Oct 4, 2015, 02:32 PM
• Last activity: Oct 31, 2023, 08:34 PM
2
votes
1
answers
1792
views
Make whiptail work in a for loop
I have a bash script that checks ping for 163 sites(stores around the country), which is this: #!/bin/bash #storestest.sh #version 0.9.2 clear; printf "Check stores procedure started; `date +"%d/%m/%Y %H:%M:%S"`\n"; declare -a STORESITE=($(cat 'stores.txt' | awk -F, '{print $1}')); # Declaring an ar...
I have a bash script that checks ping for 163 sites(stores around the country), which is this:
#!/bin/bash
#storestest.sh
#version 0.9.2
clear;
printf "Check stores procedure started;
date +"%d/%m/%Y %H:%M:%S"
\n";
declare -a STORESITE=($(cat 'stores.txt' | awk -F, '{print $1}')); # Declaring an array and populated by the file stores.txt
declare -i UP=0; # Create a variable to serve as a counter for stores that are up
declare -i DOWN=0; # Create a variable to serve as a counter for stores that are down
touch storesdown.txt; # Create a file if does not exist to store the list of the store the stores that are down
printf "" > storesdown.txt; # Clear the contents of the file
touch storesup.txt; # Create a file if does not exist to store the list of the store the stores that are up
printf "" > storesup.txt; # Clear the contents of the file
whiptail --title "Testing stores connectivity" --backtitle "Store Test" --yes-button "OK" --no-button "Cancel" --yesno "Check stores procidure has started" 10 50
if [ $? -ne 0 ]; then
exit;
fi
for i in "${STORESITE[@]}" ; do
ping -c 3 $i > /dev/null 2> /dev/null;
if [ $? -eq 0 ]; then
echo "$i is up" >> storesup.txt;
let UP++
sleep 1
else
echo "$i is down" >> storesdown.txt;
let DOWN++
sleep 1
fi
printf "Total: $UP are online and $DOWN are off line.\r";
done
echo "Total: $UP are online and $DOWN are off line.";
exit;
The above script is working fine but I decided to make it a bit fancier by adding a gauge to show the total progress of it.
So here is what I did next:
#!/bin/bash
#storestest.sh
#version 0.9.3
clear;
printf "Check stores procedure started; date +"%d/%m/%Y %H:%M:%S"
\n";
declare -a STORESITE=($(cat 'stores.txt' | awk -F, '{print $1}')); # Declaring an array and populated by the file stores.txt
declare -i UP=0; # Create a variable to serve as a counter for stores that are up
declare -i DOWN=0; # Create a variable to serve as a counter for stores that are down
touch storesdown.txt; # Create a file if does not exist to store the list of the store the stores that are down
printf "" > storesdown.txt; # Clear the contents of the file
touch storesup.txt; # Create a file if does not exist to store the list of the store the stores that are up
printf "" > storesup.txt; # Clear the contents of the file
whiptail --title "Testing stores connectivity" --backtitle "Store Test" --yes-button "OK" --no-button "Cancel" --yesno "Check stores procidure has started" 10 50
if [ $? -ne 0 ]; then
exit;
fi
total="${#STORESITE[*]}";
{
for ((g = 0; g /dev/null 2> /dev/null;
if [ $? -eq 0 ]; then
echo "$i is up" >> storesup.txt;
let UP++
sleep 2
else
echo "$i is down" >> storesdown.txt;
let DOWN++
sleep 2
fi
printf "Total: $UP are online and $DOWN are off line.\r";
done
sleep 1
echo $g
done
} | whiptail --gauge "Please wait" 6 60 0
echo "Total: $UP are online and $DOWN are off line.";
exit;
Which does not work as I thought it should be.... That was the best way I could think and write to make at least the whiptail work, but apparently what it happens is to skip the nested loop.
P.S I know some of my coding is obsolete and old fashion way of bash scripting.
ChrisH
(21 rep)
Nov 25, 2015, 01:32 AM
• Last activity: Oct 26, 2023, 05:08 PM
1
votes
2
answers
2218
views
Is there a syntax for a "for" loop over words or lines in a variable, that will work unmofdified in both bourne shell and zsh?
I have a variable that contains a list of strings, one per line, to be looped over in a `for...in...do...done` command. I move regularly between bourne shell and zsh. As far as I can understand it, zsh doesnt by default split words out of a a string at newline or whitespace; bourne shell does. So co...
I have a variable that contains a list of strings, one per line, to be looped over in a
for...in...do...done
command.
I move regularly between bourne shell and zsh. As far as I can understand it, zsh doesnt by default split words out of a a string at newline or whitespace; bourne shell does. So commands like for list_item in $list; do...
fail in zsh whereas they'd work in bourne shell, or with literal text rather than variable. Ive tried playing with IFS=
in the command, and quoting the variable, but can't seem to make progress.
Is there a single syntax for a loop over the words/lines in the string, that will work unmodified in both shells, for ease? if not, what's best practice?
Stilez
(1311 rep)
Oct 14, 2023, 10:46 AM
• Last activity: Oct 19, 2023, 02:04 PM
0
votes
3
answers
3012
views
What is the proper way to loop through each directory in a for loop?
For example, in this for loop ``` for var in ????? do dummy command done ``` I would like to be able to loop through each directory in the one that I am currently in, but it will be an unknown list of directories so I can't write every single one into where the question marks are. Any help is apprec...
For example, in this for loop
for var in ?????
do
dummy command
done
I would like to be able to loop through each directory in the one that I am currently in, but it will be an unknown list of directories so I can't write every single one into where the question marks are. Any help is appreciated.
Anonymous
(11 rep)
Jun 8, 2020, 05:24 PM
• Last activity: Aug 25, 2023, 12:34 PM
3
votes
4
answers
2426
views
execute a command recursively on the files of a folder in the matching location, not in the original one
I want to recursively convert files from `.docx` to `.doc` in a folder. The problem is that all the output files are created in the folder where I run the following command, not in the location of the source files: find -type f -name "*.docx"-exec libreoffice --convert-to doc {} \; I understand that...
I want to recursively convert files from
.docx
to .doc
in a folder. The problem is that all the output files are created in the folder where I run the following command, not in the location of the source files:
find -type f -name "*.docx"-exec libreoffice --convert-to doc {} \;
I understand that find gives source files to the libreoffice
command and the output obviously has to be in the current location, so how can I use a command to loop recursively into a folder and execute the command from the location where the files is found, not the initial one?
fich
(340 rep)
Oct 22, 2022, 05:20 PM
• Last activity: Aug 25, 2023, 10:39 AM
0
votes
1
answers
1021
views
Recursively fix corrupted video files with ffmpeg
I think I'm pretty close to having a code which will start at a directory, then spit out a fixed copy, using fd (instead of find) and ffmpeg. I have written the if statement here as psudo-code: for i in $(fd -e .mp4 -e .avi); do if [ffmpeg -v error -i "$i" -f null - 2] has an error, then ffmpeg -err...
I think I'm pretty close to having a code which will start at a directory, then spit out a fixed copy, using fd (instead of find) and ffmpeg. I have written the if statement here as psudo-code:
for i in $(fd -e .mp4 -e .avi);
do if [ffmpeg -v error -i "$i" -f null - 2] has an error, then
ffmpeg -err_detect ignore_err -i video.mkv -c copy video_fixed.mkv;
done
I believe that when you use 'fatal' if there is no fatal error, the file will be blank/zero. Which would be easier, but I think 'error' is more appropriate.
What I want to modify is to have the IF statement execute if there are errors, and do nothing if not. If there are errors it will create the video_fixed.mkv. However, I also don't want this to be video_fixed.mkv, I want it to be the same file name as $i with the same file extension as the original, and to replace the original with it. I'm also not sure if $i is just the filename, or the filename including the entire path, which makes things tricky, I'd have to capture the string after the last '/' as the file name.
If it's too hard to do the comparison, I'll have to just copy all the files regardless of if they have errors, but to do this I'll still need to name and override the copies to be the same as the originals.
Thanks
1toneboy
(465 rep)
Aug 9, 2023, 12:37 PM
• Last activity: Aug 14, 2023, 10:05 PM
Showing page 1 of 20 total questions