I would like to iterate over `dirs`in a script, but the script will never show more than one (current) folder
Code:
#! /bin/bash
for i in `dirs`
do
echo ${i}
done
echo ++++++++++++++++++
for i in $( dirs -p )
do
echo ${i}
done
echo ------------------
dirscontent=`dirs`
echo "dirs : $dirscontent"
echo ++++++++++++++++++
Prior to running the code I have cd/pushd a few folders. Running dirs in the terminal window will list more than one folder. If I type the code in the terminal window I will get the whole list of folders. How can I make it work in the script?
Last edited by alexanderb; 03-30-2019 at 07:29 AM..
Reason: >_ icode was the wrong tag, </> wrapping <code> was better
Now, I am stuck at filtering with associative arrays but I will make a separate topic if I cannot solve it.
Code:
function dirslist () {
declare -A arr
for i in ~ /usr /usr/local /usr ~ /etc
# for i in $( dirs -p )
do
echo checking ${i}
if [ ${arr[$i]+7} ] ; then
echo " ${i} exists, should not try add it again"
else
echo " adding $i to arr"
arr[ $i ]=1
fi
done
for key in "${!arr[@]}"; do
echo "Key: $key"
done
}
Moderator's Comments:
Posting "Does not work" or "I am stuck" without explanation does not help you or anyone. If a command does not work for you, please show the exact circumstances you used it, and the exact error or malfunction you received. Do not paraphrase errors, or post the text as links, images, or attachments if you can avoid it: Paste the exact message, in code tags, like [code] text [/code] or by selecting the text and using the button.
Thank you.
The UNIX and Linux Forums
Last edited by RudiC; 03-30-2019 at 02:24 PM..
This User Gave Thanks to alexanderb For This Post:
Please become accustomed to provide decent context info of your problem.
It is always helpful to carefully and detailedly phrase a request, and to support it with system info like OS and shell, related environment (variables, directory structures, options), preferred tools, adequate (representative) sample input and desired output data and the logics connecting the two including your own attempts at a solution, and, if existent, system (error) messages verbatim, to avoid ambiguities and keep people from guessing.
Where are you stuck? Running your given script yields
I apologize for the non satisfactory context. I did not solve how to use associative arrays as a lookup table and used an ordinary array instead.
Context, operating system, bash version
More than 20 years ago, at the release of bash 2.0, I redefined the cd function and I have used my own version of cd ever since on various solaris, bsd and linux systems. Typing cd without any arguments would list the top 7 directories of DIRSTACK and typing cd with a number argument would change directory using the DIRSTACK. It was slightly annoying that the top of DIRSTACK did not necessarily contain unique directories but my cd function was good enough for usage and I never got around to refining it.
The other day I noticed that bash has evolved and now has associative arrays which I thought would solve the issue with the potentially repetitive directory listing.
The problem
I do not know how to check if a key already exists in an associative array. The exotic ${arr[$i]+7} was something I tried reading
wiki.nix-pro.com/view/BASH_associative_arrays#Check_if_key_exists
The basic algorithm I want to do is
Code:
foreach directory in DIRSTACK
if the directory has not been presented to the user
present the directory to the user
remember (i.e. store) the directory
which in a sample test code would be
Code:
function dirlist () {
declare -A arr
for i in /usr /usr/local /usr "/foldername with spaces" "/foldername with spaces"
do
echo checking ${i}
if [[ ${arr[$i]} != 17 ]] ; then
echo " handling $i and adding it to arr"
arr[ $i ]=17
fi
done
}
The above program yields
Code:
checking /usr
handling /usr and adding it to arr
checking /usr/local
handling /usr/local and adding it to arr
checking /usr
handling /usr and adding it to arr
checking /foldername with spaces
handling /foldername with spaces and adding it to arr
checking /foldername with spaces
handling /foldername with spaces and adding it to arr
but what I expected (hoped) it to print was
Code:
checking /usr
handling /usr and adding it to arr
checking /usr/local
handling /usr/local and adding it to arr
checking /foldername with spaces
handling /foldername with spaces and adding it to arr
The workaround
I rewrote my old cd function using a simple array for lookup instead of an associated array. The performance hit is negligible but it is annoying that I could not get the associated array to work. It was not without pain to implement since I haven't done any bash programming in 20 years. My new cd function seems to work all right though I haven't tested it extensively. I provide it here for context.
Code:
unset -f cd
function cd () {
local -i maxnrDirs=7
local -i nrDirs=0 # index of dirs as shown to user
local visited=()
local -i founddir=0
# if argument is a valid directory , change directory
if [ -d "$1" ]; then
pushd "$1" > /dev/null;
else
for ((i=1; i < ${#DIRSTACK[@]}; i++)); do
# keep track of already listed directories,
# Note, should be done with associative array
# this was on my TODO list for 20 years
local -i found=0
for ((j=0; j < ${#visited[@]}; j++)); do
if [[ ${visited[$j]} == ${DIRSTACK[${i}]} ]]
then
found=17
break
fi
done
# handle directory option if not found
if [ $found == 0 ] ; then
((nrDirs+=1))
# if there is no argument to cd, list previous dirs
if [ -z "$1" ]; then
founddir=17
echo " $nrDirs ${DIRSTACK[$i]}";
# if there is a number argument, check against DIRSTACK
else
if [ "$1" == ${nrDirs} ]; then
if [ "${DIRSTACK[${i}]}" ]; then
if [ -d "`dirs -l +${i}`" ]; then
pushd "`dirs -l +${i}`" > /dev/null ;
founddir=${i};
fi;
fi;
fi;
fi
local dir=${DIRSTACK[$i]} # for quoting directory with spaces
visited+=("$dir") # visited+=("${DIRSTACK[$i]}") does not work
if [ $nrDirs == $maxnrDirs ]; then
break;
fi
fi
done;
if [ ${founddir} == 0 ]; then
# Handle special characters, invent new ones ....?
if [ "$1" == - ]; then
pushd "`dirs -l +1`" > /dev/null;
elif [ "$1" == "..." ]; then
if [ -d "../../" ]; then
pushd "../../../" > /dev/null ;
fi
elif [ "$1" == "...." ]; then
if [ -d "../../../" ]; then
pushd "../../../" > /dev/null ;
fi
elif [ ! -z "$1" ]; then
# error message, TODO check \ ??
echo ${1} not a valid directory;
fi;
fi;
fi
}
complete -A directory cd
complete -A directory pushd
and here is a sample how it works
Code:
/> export PS1='\w> '
/> cd /
/> dirs -c
/> cd /usr/
/usr> cd local/
/usr/local> cd /etc/
/etc> cd cron.d/
/etc/cron.d> cd
1 /etc
2 /usr/local
3 /usr
4 /
/etc/cron.d> cd 2
/usr/local> cd -
/etc/cron.d> cd
1 /usr/local
2 /etc/cron.d
3 /etc
4 /usr
5 /
/etc/cron.d> dirs -p
/etc/cron.d
/usr/local
/etc/cron.d
/etc
/usr/local
/usr
/
Wow, that's intricate and certainly beyond me on first sight. A few comments:
- You don't need to check if an index is already represented in an associative array; just assign it. If it's aready there, it's overwritten, if not, added.
- your cd without parameter naturally lends itself to bash's select statement; see below (as a proof of concept; it just echoes the cd, no error checking etc.). Note the duplicate /usr entry:
Code:
echo ${DIRSTACK[@]}
/usr /etc/network /home/myuser /usr /mnt/9/plgr
declare -A TMP
for DN in ${DIRSTACK[@]}; do TMP[$DN]=1; done
select R in ${!TMP[@]}; do echo cd $R; break; done
1) /usr
2) /home/myuser
3) /etc/network
4) /mnt/9/plgr
#? 3
cd /etc/network
Have two 3 files which has list of servers,users and location and base url which is common on every server
A = server1 server2 server3
B = user1 user2 user3
C = dom1 dom2 dom3
baseurl=/opt/SP/
and what i have to achieve is below via ssh from REMOTE SERVER
for it's first iteration it... (7 Replies)
Hi guys,
I am having trouble with this script. What i want it to do is to iterate all command line arguments in reverse order. The code below does this fine but i need the output to print the words on separate lines instead of one line:
#!/bin/bash
#Takes in the arguments and displays them... (7 Replies)
Hi
i need to find x in the following equation such that it satisfies this condition:
y/x-ln(x)-1.24=0
how can i write a script to iterate to give random x to satisfy this equation.
y is different each time too. any help with awk/shell script will be awesome!
thanks (1 Reply)
I am trying to get a listing of ALL directories only under /export (as an example). I can get all the dirs directly under /export but I need any sub dirs under those dirs. I've looked (here and google) but can not find anything that works (4 Replies)
Hi Experts,
I want to know the count of specific word in a file. I have almost 600+ files.
So I want to loop thru each file and get the count of the specific word.
Please help me on achieving this...
Many thanks (2 Replies)
Basically, I have a perl script that calls enables one to resume where a video file left off (i.e. where the user stopped playback) that chokes on files that are located in a path that contains spaces.
To make the situation a little more complicated, the perl script gets help from a bash script... (6 Replies)
I have a directory which is /home/mark/files/ , inside this particular I have a bunch of filles (see examples below)
TST_SHU_00014460_20090302.txt
TST_SHU_00016047_20090302.txt
TST_SHU_00007838_20090303.txt
TST_SHU_00056485_20090303.txt
TST_SHU_00014460_20090303.txt... (2 Replies)
I'm trying to iterate a UNIX awk script that returns min/max temperature data for each day from a monthly weather data file (01_weath.dat). The temperature data is held in $5. The temps are reported each minute so each day contains 1440 temperature enteries. The below code has gotten me as far as... (5 Replies)
hi,
I would like to know of a shell script to create the following
A script which will take in two parameters i.e. name of file and SID and create directories named /opt/oracle/admin/$SID/{bdump,cdump,udump}. Then edit the init file and change the three lines that look like this.
... (2 Replies)