I was wondering if there is a way to save the current package selections for cygwin for a later reinstall or porting on a different system.
It would be really great to:
run a command to export a list of installed packages on an existing system
pass the list to the installer on another system in a way such as setup-x86_64.exe --list list.txt
I don't think the setup has such a switch, so even any type of script or batch working in this direction would be just fine.
Since the number of needed packages is very high, it should be unattended in order to consider it as a good solution!
What would be the best way to accomplish a quick reinstall like this?
The list of installed packages is available with cygcheck. Setup does not accept a list option but you can specific the list with -P
The following code, when used with -A option will create
a crafted cyg-reinstall-${Arch}.bat batch file to install all
packages existing in a system.
#!/bin/bash
# Create a batch file to reinstall using setup-{ARCH}.exe
# all packages reported as incomplete
print_error=1
if [ $# -eq 1 ]
then
if [ $1 == "-I" ]
then
lista=$(mktemp)
cygcheck -c | grep "Incomplete" > $lista
print_error=0
fi
if [ $1 == "-A" ]
then
lista=$(mktemp)
cygcheck -cd | sed -e "1,2d" > $lista
print_error=0
fi
fi
if [ $# -eq 2 ]
then
if [ $1 == "-f" ]
then
lista=$2
print_error=0
fi
fi
# error message if options are incorrect.
if [ $print_error -eq 1 ]
then
echo -n "Usage : " $(basename $0)
echo " [ -A | -I | -f filelist ]"
echo " create cyg-reinstall-{ARC}.bat from"
echo " options"
echo " -A : All packages as reported by cygcheck"
echo " -I : incomplete packages as reported by cygcheck"
echo " -f : packages in filelist (one per raw)"
exit 1
fi
if [ $(arch) == "x86_64" ]
then
A="x86_64"
else
A="x86"
fi
# writing header
echo -n -e "setup-${A}.exe " > cyg-reinstall-${A}.bat
# option -x remove and -P install
# for re-install packages we need both
if [ $1 == "-I" ]
then
awk 'BEGIN{printf(" -x ")} NR==1{printf $1}{printf ",%s", $1}' ${lista} >> cyg-reinstall-${A}.bat
fi
awk 'BEGIN{printf(" -P ")} NR==1{printf $1}{printf ",%s", $1} END { printf "\r\n pause "}' ${lista} >> cyg-reinstall-${A}.bat
# execution permission for the script
chmod +x cyg-reinstall-${A}.bat
I recognize that this question is several years old, but I've often found useful information on here from even longer ago, so this might still help someone someday.
The script above did not work for me; I suspect the list was too long, or something of that nature. So I kept trying things, and I eventually arrived at a shell one-liner that worked correctly by trimming the list to only those items that I had explicitly requested. The key came from #Andrey's comment above: /etc/setup/installed.db!
Here's the command I used:
(ORIG_PKGS="/path/to/other-cygwin64/etc/setup/installed.db" ; PKGS=$(awk '/ 1$/ {print $1}' "${ORIG_PKGS}") ; PLIST=$(tr '\n' ',' <<< "${PKGS}") ; /setup-x86_64 -q -P "${PLIST%%,}")
For readability, here it is split up into multiple lines:
ORIG_PKGS="/path/to/other-cygwin64/etc/setup/installed.db"
PKGS=$(awk '/ 1$/ {print $1}' "${ORIG_PKGS}")
PLIST=$(tr '\n' ',' <<< "${PKGS}")
/setup-x86_64 -q -P "${PLIST%%,}"
All you should need is the /etc/setup/installed.db from the previous Cygwin installation; just alter the value of ORIG_PKGS with the correct path to that file, and the rest should Just Work®!
Related
I am a beginner and trying to write a script that takes a config file (example below) and sets the rights for the users, if that user or group doesn´t exist, they get added.
For every line in the file, I am cutting out the user or the group and check if they exist.
Right now I only check for users.
#!/bin/bash
function SetRights()
{
if [[ $# -eq 1 && -f $1 ]]
then
for line in $1
do
var1=$(cut -d: -f2 $line)
var2=$(cat /etc/passwd | grep $var1 | wc -l)
if [[ $var2 -eq 0 ]]
then
sudo useradd $var1
else
setfacl -m $line
fi
done
else
echo Enter the correct path of the configuration file.
fi
}
SetRights $1
The config file looks like this:
u:TestUser:- /home/temp
g:TestGroup:rw /home/temp/testFolder
u:TestUser2:r /home/temp/1234.txt
The output:
grep: TestGroup: No such file or directory
grep: TestUser: No such file or directory
"The useradd help menu"
If you could give me a hint what I should look for in my research, I would be very grateful.
Is it possible to reset var1 and var2? Using unset didn´t work for me and I couldn´t find variables could only be set once.
It's not clear how you are looping over the contents of the file -- if $1 contains the file name, you should not be seeing the errors you report.
But anyway, here is a refactored version which hopefully avoids your problems.
# Avoid Bash-only syntax for function definition
SetRights() {
# Indent function body
# Properly quote "$1"
if [[ $# -eq 1 && -f "$1" ]]
then
# Read lines in file
while read -r acl file
do
# Parse out user
user=${acl#*:}
user=${user%:*}
# Avoid useless use of cat
# Anchor regex correctly
if ! grep -q "^$user:" /etc/passwd
then
# Quote user
sudo useradd "$user"
else
setfacl -m "$acl" "$file"
fi
done <"$1"
else
# Error message to stderr
echo Enter the correct path of the configuration file. >&2
# Signal failure to the caller
return 1
fi
}
# Properly quote argument
SetRights "$1"
I've spent some time trying to figure this out with various internet searches and digging through stackoverflow. I'll try to explain this as best as a noob can.
I have a script that searches a config repository directory that is populated with directories for every Juniper and Cisco router and switch we have deployed. Each device directory has a file or two that I'm interested in, "show.version" and "show.chassis.hardware", except when they don't. The second file, "show.chassis.hardware" is not a command that Cisco boxes has, so that file does not exist in Cisco device directories. There also isn't a naming scheme that can easily tell me if the device is Juniper or Cisco, which is also part of the reason why my script exists.
To make things more fun, different models and even software versions output the show.version file in different formats (for both Cisco and Juniper), so my awk is full of all the different fields we will encounter.
Script:
#!/usr/local/bin/zsh
svn="$HOME/svn/nw_config_data/"
case "$1" in
("-a")
hosts=""
;;
("-b")
hosts=".bb.domain.net"
;;
("-c")
hosts=".cpe.domain.net"
;;
("-e")
hosts=".etech.domain.net"
;;
("-k")
hosts=".core.domain.net"
;;
("-m")
hosts=".maint.domain.net"
;;
("-o")
hosts=".ohgov.domain.net"
;;
esac
dirs=($(ls -d $svn*$hosts*))
for hostdir in $dirs
do host=$(echo $hostdir | grep -Eo "(\w|\.|-)*$")
awk -v h=$host '/^Model/{m=$2} /^Model number/{m=$4} /^\*0/{m=$2}
/^JUNOS Base OS boot/{v=$5} /^Junos:/{v="["$2"]"} /^BOOTLDR:/{v=$7}
/^JUNOS EX Software Suite/{v=$5} /^ROM:/{v=$5} /^JUNOS Software
Release/{v=$4} /^Chassis/{s=$2} /^Motherboard serial number/{s=$3}
END {if(m!="number") {printf("%s %s %s %s\n",h,m,v,s)}}'
"$hostdir/show.version" "$hostdir/show.chassis.hardware"
done
What it looks like when I run the script:
% cver -b
device1-e0.bb.domain.net ex4300-24t [14.1X53-D25.2] Serial#
device2-e0.bb.domain.net ex4300-24t [14.1X53-D25.2] Serial#
awk: can't open file /home/clmbn eng2/a/rwalker/svn/nw_config_data/device3-e1.bb.domain.net/show.chassis.hardware
input record number 55, file /home/clmbn-eng2/a/rwalker/svn/nw_config_data/device3-e1.bb.domain.net/show.chassis.hardware
source line number 1
device4-r0.bb.domain.net m7i [13.3R6.5] Serial#
...
What I want it to look like
% cver -b
device1-e0.bb.domain.net ex4300-24t [14.1X53-D25.2] Serial#
device2-e0.bb.domain.net ex4300-24t [14.1X53-D25.2] Serial#
device3-e1.bb.domain.net C3750 12.1(14r)EA1a, Serial#
device4-r0.bb.domain.net m7i [13.3R6.5] Serial#
...
I have 13 directories that do not have the "show.chassis.hardware" file but do have the "show.version" file which does have all the information I need from it. I have one directory that has no files, but it doesn't matter because that device is going to be replaced.
From what I've been reading, awk might not be able to do this, but I have faith that someone out there knows a way to make it work. If my approach (shell & awk scripting) just isn't going to work and I need to do it in something else (Perl or Python for example) I'll be completely stuck until I can learn those enough to convert my script to one of those languages.
Also, we don't have bash installed on this server and I don't know when we will since I'm not the admin.
You need
-f file
true if file exists and is a regular file.
if [[ -f "$hostdir/show.version" && -f "$hostdir/show.chassis.hardware" ]]; then
# your awk command goes here...
awk '{ }' "$hostdir/show.version" "$hostdir/show.chassis.hardware"
else
echo "not enough files found"
fi
You may refer : http://zsh.sourceforge.net/Doc/Release/Conditional-Expressions.html
--edit--
That's cool that this bit of script skips the directories that doesn't
have the file, but it doesn't pull the information from the
"show.version" file and print that information anyway. So the output
shows device1, device2, device 4...
Here is code snippet
function myfunc(){
# replace with your awk
awk '{ print }' "$#"
}
if [[ -f "$hostdir/show.version" && -f "$hostdir/show.chassis.hardware" ]]; then
# your awk command goes here...
myfunc "$hostdir/show.version" "$hostdir/show.chassis.hardware"
else
echo "not enough files found"
# pass only one file, version file
myfunc "$hostdir/show.version"
fi
You can use zsh's (...|...) globbing:
$ mkdir foo bar; touch {foo,bar}/show.version foo/show.chassis.hardware
$ echo foo/show.(version|chassis.hardware)
foo/show.chassis.hardware foo/show.version
$ echo bar/show.(version|chassis.hardware)
bar/show.version
Since this is globbing, it will only expand to existing files. So your awk command would look like:
awk -v h=$host '/^Model/{m=$2} ... END {...}' "$hostdir"/show.(version|chassis.hardware)
(omitting the awk script for readability)
I'd also simplify your script a bit using associative arrays instead of cases:
#!/usr/local/bin/zsh
usage () {
echo "Help!" # echo your help message here
exit $1
}
svn="$HOME/svn/nw_config_data/"
declare -A hosts # make associative array
hosts["-a"]=""
hosts["-b"]=".bb.domain.net"
hosts["-c"]=".cpe.domain.net"
hosts["-e"]=".etech.domain.net"
hosts["-k"]=".core.domain.net"
hosts["-m"]=".maint.domain.net"
hosts["-o"]=".ohgov.domain.net"
if [[ $1 == -h ]]
then
usage
elif (( ${+hosts["$1"]} )) # check if $1 is a key in hosts
then
echo "Invalid option: $1"
usage 1 # exit with status 1 to indicate error
fi
dirs=( $svn*$hosts["$1"]* ) # no need for ls here
for hostdir in $dirs
do
host=$(echo $hostdir | grep -Eo "(\w|\.|-)*$")
awk -v h=$host '
/^Model/{m=$2}
/^Model number/{m=$4}
/^\*0/{m=$2}
/^JUNOS Base OS boot/{v=$5}
/^Junos:/{v="["$2"]"}
/^BOOTLDR:/{v=$7}
/^JUNOS EX Software Suite/{v=$5}
/^ROM:/{v=$5}
/^JUNOS Software Release/{v=$4}
/^Chassis/{s=$2}
/^Motherboard serial number/{s=$3}
END {if(m!="number") {printf("%s %s %s %s\n",h,m,v,s)}}' \
"$hostdir"/show.(version|chassis.hardware)
done
Alternately, you can use a concise case with the array:
declare -A hosts # make associative array
hosts["-a"]=""
hosts["-b"]=".bb.domain.net"
hosts["-c"]=".cpe.domain.net"
hosts["-e"]=".etech.domain.net"
hosts["-k"]=".core.domain.net"
hosts["-m"]=".maint.domain.net"
hosts["-o"]=".ohgov.domain.net"
case $1 in
-[abcekmno]) dirs=( $svn*${hosts["$1"]}* )
;;
-h|help) usage
;;
*) echo "Invalid option: $1"
usage 1 # exit with status 1 to indicate error
;;
esac
How can I add in bash a test checking if a given directory (say /usr/local/bin) is already in a variable, say $PATH, before actually doing it?
Context: I am creating a script for a package I maintain for which I wish to include all steps to install dependencies. This involves changing the $PATH variable, but my question is more general (changes involve also $PYTHONPATH for instance). However, I wish also to not mingle with the existing variables and to not prepend it if it already exists.
Using grep you can test
echo "$PATH" | grep -o '/usr/local/bin'
Example:
var=$(echo $PATH | grep -o '/usr/local/bin')
if [ -n "$var" ] ; then
echo 'already Existe'
else
echo 'Not exists'
fi
Output:
already Existe
You can check like this:
export p='/usr/local/bin'
(IFS=: a=("$PATH"); printf "%s\n" "${a[#]}"|grep -xq "$p") && echo "exists" || echo "nope"
exists
export p='/usr/local/bin123'
(IFS=: a=("$PATH"); printf "%s\n" "${a[#]}"|grep -xq "$p") && echo "exists" || echo "nope"
nope
grep options used:
-x -> exact match
-q -> quiet, just returns exit status
So I have been struggling with this task for eternity and still don't get what went wrong. This program doesn't seem to download ANY pdfs. At the same time I checked the file that stores final links - everything stored correctly. The $PDFURL also checked, stores correct values. Any bash fans ready to help?
#!/bin/sh
#create a temporary directory where all the work will be conducted
TMPDIR=`mktemp -d /tmp/chiheisen.XXXXXXXXXX`
echo $TMPDIR
#no arguments given - error
if [ "$#" == "0" ]; then
exit 1
fi
# argument given, but wrong format
URL="$1"
#URL regex
URL_REG='(https?|ftp|file)://[-A-Za-z0-9\+&##/%?=~_|!:,.;]*[-A-Za-z0-9\+&##/%=~_|]'
if [[ ! $URL =~ $URL_REG ]]; then
exit 1
fi
# go to directory created
cd $TMPDIR
#download the html page
curl -s "$1" > htmlfile.html
#grep only links into temp.txt
cat htmlfile.html | grep -o -E 'href="([^"#]+)\.pdf"' | cut -d'"' -f2 > temp.txt
# iterate through lines in the file and try to download
# the pdf files that are there
cat temp.txt | while read PDFURL; do
#if this is an absolute URL, download the file directly
if [[ $PDFURL == *http* ]]
then
curl -s -f -O $PDFURL
err="$?"
if [ "$err" -ne 0 ]
then
echo ERROR "$(basename $PDFURL)">&2
else
echo "$(basename $PDFURL)"
fi
else
#update url - it is always relative to the first parameter in script
PDFURLU="$1""/""$(basename $PDFURL)"
curl -s -f -O $PDFURLU
err="$?"
if [ "$err" -ne 0 ]
then
echo ERROR "$(basename $PDFURLU)">&2
else
echo "$(basename $PDFURLU)"
fi
fi
done
#delete the files
rm htmlfile.html
rm temp.txt
P.S. Another minor problem I have just spotted. Maybe the problem is with the if in regex? I pretty much would like to see something like that there:
if [[ $PDFURL =~ (https?|ftp|file):// ]]
but this doesn't work. I don't have unwanted parentheses there, so why?
P.P.S. I also ran this script on URLs beginning with http, and the program gave the desired output. However, it still doesn't pass the test.
I created a bash script to transfer my zones between my primary and secondary DNS server.
It downloads my zone list from the primary and checks for any new zones and then downloads and inserts those zone files into the zone directory and into the .local file for bind.
The problem I have is that if the zone file does not exist, the script will enter the details into the .local regardless of if this config already exists or not.
Can someone help me out to distinguish between zones that already exist and simply download the zone file.
I have pasted my script below and if anyone has any queries on how it works, please feel free to ask.
(can someone wrap the code please, it never works properly for me in any browser I try!)
#!/bin/sh
NAMED="/etc/bind/named.conf.local"
TMPNAMED="/tmp/zns-441245.temp"
TMPZONEFILE="/tmp/zones.txt"
TMP="/tmp/zns-732.temp"
ZONELOCATION="/var/cache/bind"
IGNORE=`cat ignore.txt`
logger DNS Update script running...
echo -n "Checking for new named.conf... "
wget -q http://91.121.75.205:10801/named/named.conf -O $TMPNAMED
if [ -e $TMPNAMED ]
then
echo "done."
else
echo "no new data!"
exit
fi
echo -n "Generating zone names... "
grep "^zone" $TMPNAMED | cut -d " " -f "2" | cut -d "\"" -f 2 > $TMPZONEFILE
sed '1,5d' $TMPZONEFILE > $TMP
mv $TMP $TMPZONEFILE
echo "done. ("$TMPZONEFILE")"
echo "Generating zone info... "
grep -vf ignore.txt $TMPZONEFILE | while read ZONE; do
echo -n "Checking for $ZONELOCATION/$ZONE.db "
if [ -e $ZONELOCATION/$ZONE.db ]
then
echo "[ exists ]"
else
export updates="yes"
echo "[ doesn't exist ]"
echo "New zone available ($ZONE)... "
echo "zone \"$ZONE\" {
type slave;
file \"$ZONELOCATION/$ZONE.db\";
masters { 91.121.75.205; };
allow-notify { 91.121.75.205; };
};" >> $NAMED
fi
done
echo "Updating Bind configuration... "
/etc/init.d/bind9 restart
rm $TMPZONEFILE
rm $TMPNAMED
One problem may be that your wget creates a file regardless of whether there's a source file so checking for existence will always be true.
if [ -s $TMPNAMED ]
then
echo "done." # file exists AND has data
else
echo "no new data!"
exit
fi
will test to see if it's empty or non-existent and exit if so. This may be an issue with your if [ -e $ZONELOCATION/$ZONE.db ] as well.
sed or awk could do all of this in one line:
grep "^zone" $TMPNAMED | cut -d " " -f "2" | cut -d "\"" -f 2 > $TMPZONEFILE
sed '1,5d' $TMPZONEFILE > $TMP
but I would need to see some sample data to offer a solution.
Simplified quoting:
echo "done. ($TMPZONEFILE)"
You're not using the IGNORE variable or the updates variable. I don't see any reason to export it. Also, if you are relying on it elsewhere, its value won't survive once the while loop exits since piping something (grep in this case) into while sets up a subshell. It may be better to do one of these:
Bash:
while ...
do
...
done <(grep -vf ignore.txt $TMPZONEFILE)
sh:
grep -vf ignore.txt $TMPZONEFILE > tmp.out
while ...
do
...
done < tmp.out
I recommend using mktemp or tempfile to create temporary files, by the way.
This might be more readable and allows you to include quotes without having to escape them:
cat << EOF >> "$NAMED"
zone "$ZONE" {
type slave;
file "$ZONELOCATION/$ZONE.db";
masters { 91.121.75.205; };
allow-notify { 91.121.75.205; };
};
EOF
It's always a good habit to quote variables that contain filenames.
If you're going to all of that trouble to synchronise named.conf you might just as well rsync the whole config including the zone files, and not bother using zone transfers between primary and secondary.
It's by no means mandatory to use AXFR to slave servers. If you've got administrative control over all of the servers for a zone it's quite acceptable to treat them all as masters.