Are there any UNIX environment variables longer than four characters? - unix

I know there is $USER, $HOME, $PATH, etc.

There are plenty: DBUS_SESSION_BUS_ADDRESS, XAUTHORITY, GDM_LANG, etc. You can view all your environment variables with the env command - type it in inside a terminal.
As far as I know, there's no limitations on environment variables, they can be of any length, and anything can create them and add them to the environment (using export, as you may have seen). Conceptually, environment variables act as "global variables" that are shared among all programs running in a terminal.

Err... lots?
$ env | cut -d = -f 1 | sort | uniq
_
COLORFGBG
DBUS_SESSION_BUS_ADDRESS
DESKTOP_SESSION
DISPLAY
DM_CONTROL
EDITOR
GPG_AGENT_INFO
GS_LIB
GTK2_RC_FILES
GTK_RC_FILES
HISTCONTROL
HOME
KDE_FULL_SESSION
KDE_MULTIHEAD
KDE_SESSION_UID
KDE_SESSION_VERSION
KONSOLE_DBUS_SERVICE
KONSOLE_DBUS_SESSION
LANG
LANGUAGE
LESSCLOSE
LESSOPEN
LIBGL_DRIVERS_PATH
LOGNAME
LS_COLORS
OLDPWD
PATH
PROFILEHOME
PWD
QT_PLUGIN_PATH
SESSION_MANAGER
SHELL
SHLVL
SSH_AGENT_PID
SSH_AUTH_SOCK
TERM
USER
WINDOWID
WINDOWPATH
XCURSOR_THEME
XDG_DATA_DIRS
XDG_SESSION_COOKIE
XDM_MANAGED

Yep, $SHELL is one of them that I know of.
Edit: see this page for more of them.

How about $DISPLAY and $LD_LIBRARY_PATH.

Every system is configured differently so rather than listing them all here, just enter the following command to list them all on your own system:
set | sed 's/=.*//' | grep -v "^[A-Z_]\{4\}$"
I'd use set instead of env as it has greater scope. Most system environment variables are in upper case so to add that restriction add an extra grep to the pipe line.
set | sed 's/=.*//' | grep "[A-Z_]" | grep -v "^[A-Z_]\{4\}$"

env | cut -d = -f 1 | grep -E "([A-Z_]{4,})"
Use this command

$LD_LIBRARY_PATH and $LD_PRELOAD both exist for linking.

User defined environment variables don't have to four characters long (ex. CLASSPATH)

Related

Getting the previous working directory value

here is my simple command.
ls -lrth ../ | grep file | awk -F" " -v orig=`cd .. | pwd ` -v sort=`pwd` '{print $NF "," $7"/"$8"/"$9","orig"," sort }'
I'm trying to get the value of my previous path just above my current working directory.
current working directory = /home/PC1/Environment/Test1
what i want to get the value of pwd is /home/PC1/Environment and not want to hardcode it.
i tried to use cd .. | pwd but it still displays my current working directory not my previous working directory
can anyone help? some suggestions would be nice.
Use $(cd .. && pwd). You can also use $(cd - && pwd) to get your previous working directory even if it wasn't the parent of your current one. (In general, you should use $(...) instead of `...` to get command output; the latter interferes with quoting and doesn't nest, so can cause surprising results).
Your cd | pwd runs the cd and the pwd at the same time in different subshells, which is not what you want.

terminal command to act on filenames that don't contain text

I have a directory full of files with names such as:
file_name_is_001
file_name_001
file_name_is_002
file_name_002
file_name_is_003
file_name_003
I want to copy only the files that don't contain 'is'. I'm not sure how to do this. I have tried to search for it, but can't seem to google the right phrase to find the results.
Details depend on operating system, shell, etc.
For a unix system a quite verbose but easy to understand approach could look like this (please mind that I didn't test it):
mkdir some_temporary_directory
mv *_is_* some_temporary_directory
cp * where_ever_you_want_to_copy_it
mv some_temporary_directory/* .
rmdir some_temporary_directory
You can do this using bash. First, here's a command to get you a list of files that don't contain the text _is_:
ls | grep -v "_is_"
This takes the output of ls and matches all values with DO NOT contain _is_ using grep -v.
In order to then copy these files, we need to turn the lines output by grep into arguments of cp. We can do this using xargs:
ls | grep -v "_is_" | xargs -J % cp % new_folder
From the xargs man page, it is a tool to "build and execute command lines from standard input".

Making the "ls" command sort "a" before "B" (vs a->b->A->B)

I am trying to find a way to have the results of an ls command be printed in a case insensitive manner.
currently an ls command results in:
Apple
Boy
Chart
Dock
apples
boys
charts
docks
what i want is this:
Apple
apples
Boy
boys
Chart
charts
Dock
docks
is this possible?
ls (at least if you're using the GNU coreutils version; ls --version to check that) sorts file names according to the current locale.
The set of available locales varies from system to system (locale -a for a list), but on my system this:
LC_COLLATE=en_US.utf8 ls
sorts names with a and A before b and B -- though it might not be exactly in the order you're looking for.
This works even when ls lists files in multiple columns, something that's difficult to do with sort -f.
(I have $LC_COLLATE set to C specifically so that locale-sensitive sorting is done in ASCII order.)
Just pipe the result to sort -f.
As a follow up to [Keith Thompson]'s answer, I tested on a Linux system and LC_COLLATE=C did not work for me, but LC_COLLATE="en_US.UTF-8" did. I put the following in my startup script:
export LANG=en_US.UTF-8
export LC_COLLATE="en_US.UTF-8"
This did not work on OS X.
# alias ll='(LC_COLLATE=en_US.utf8 && export LC_COLLATE && shopt -s nocaseglob && /bin/ls -alF --color=auto )'
# ll
ls --format=single-column | sort -f
Add to .profile:
alias llg='ls -ltr | grep -i'
then you can use following command:
llg "week"

Unix [Homework]: Get a list of /home/user/ directories in /etc/passwd

I'm very new to Unix, and currently taking a class learning the basics of the system and its commands.
I'm looking for a single command line to list off all of the user home directories in alphabetical order from the /etc/passwd directory. This applies only to the home directories, and not the contents within them. There should be no duplicate entries. I've tried many permutations of commands such as the following:
sort -d | find /etc/passwd /home/* -type -d | uniq | less
I've tried using -path, -name, removing -type, using -prune, and changing the search pattern to things like /home/*/$, but haven't gotten good results once. At best I can get a list of my own directory (complete with every directory inside it, which is bad), and the directories of the other students on the server (without the contained directories, which is good). I just can't get it to display the /home/user directories and nothing else for my own account.
Many thanks in advance.
/etc/passwd is a file. the home directory is usually at field/column 6, where ":" is the delimiter. When you are dealing with file structure that has distinct characters as delimiters, you should use a tool that can break your data down into smaller chunks for easier manipulation using fields and field delimiters. awk/cut etc, even using the shell with IFS variable set can do the job. eg
awk -F":" '{print $6}' /etc/passwd | sort
cut -d":" -f6 /etc/passwd |sort
using the shell to read the file
while IFS=":" read -r a b c d e home_dir g
do
echo $home_dir
done < /etc/passwd | sort
I think the tools you want are grep, tr and awk. Grep will give you lines from the file that actually contain home directories. tr will let you break up the delimiter into spaces, which makes each line easier to parse.
Awk is just one program that would help you display the results that you want.
Good luck :)
Another hint, try ls --color=auto /etc, passwd isn't the kind of file that you think it is. Directories show up in blue.
In Unix, find is a command for finding files under one or more directories. I think you are looking for a command for finding lines within a file that match a pattern? Look into the command grep.
sed 's|\(.[^:]*\):\(.[^:]*\):\(.*\):\(.[^:]*\):\(.[^:]*\)|\4|' /etc/passwd|sort
I think all this processing could be avoided. There is a utility to list directory contents.
ls -1 /home
If you'd like the order of the sorting reversed
ls -1r /home
Granted, this list out the name of just that directory name and doesn't include the '/home/', but that can be added back easily enough if desired with something like this
ls -1 /home | (while read line; do echo "/home/"$line; done)
I used something like :
ls -l -d $(cut -d':' -f6 /etc/passwd) 2>/dev/null | sort -u
The only thing I didn't do is to sort alphabetically, didn't figured that yet

How to do a mass rename?

I need to rename files names like this
transform.php?dappName=Test&transformer=YAML&v_id=XXXXX
to just this
XXXXX.txt
How can I do it?
I understand that i need more than one mv command because they are at least 25000 files.
Easiest solution is to use "mmv"
You can write:
mmv "long_name*.txt" "short_#1.txt"
Where the "#1" is replaced by whatever is matched by the first wildcard.
Similarly #2 is replaced by the second, etc.
So you do something like
mmv "index*_type*.txt" "t#2_i#1.txt"
To rename index1_type9.txt to t9_i1.txt
mmv is not standard in many Linux distributions but is easily found on the net.
If you are using zsh you can also do this:
autoload zmv
zmv 'transform.php?dappName=Test&transformer=YAML&v_id=(*)' '$1.txt'
You write a fairly simple shell script in which the trickiest part is munging the name.
The outline of the script is easy (bash syntax here):
for i in 'transform.php?dappName=Test&transformer=YAML&v_id='*
do
mv $i <modified name>
done
Modifying the name has many options. I think the easiest is probably an awk one-liner like
`echo $i | awk -F'=' '{print $4}'`
so...
for i in 'transform.php?dappName=Test&transformer=YAML&v_id='*
do
mv $i `echo $i | awk -F'=' '{print $4}'`.txt
done
update
Okay, as pointed out below, this won't necessarily work for a large enough list of files; the * will overrun the command line length limit. So, then you use:
$ find . -name 'transform.php?dappName=Test&transformer=YAML&v_id=*' -prune -print |
while read
do
mv $reply `echo $reply | awk -F'=' '{print $4}'`.txt
done
Try the rename command
Or you could pipe the results of an ls into a perl regex.
You may use whatever you want to transform the name (perl, sed, awk, etc.). I'll use a python one-liner:
for file in 'transform.php?dappName=Test&transformer=YAML&v_id='*; do
mv $file `echo $file | python -c "print raw_input().split('=')[-1]"`.txt;
done
Here's the same script entirely in Python:
import glob, os
PATTERN="transform.php?dappName=Test&transformer=YAML&v_id=*"
for filename in glob.iglob(PATTERN):
newname = filename.split('=')[-1] + ".txt"
print filename, '==>', newname
os.rename(filename, newname)
Side note: you would have had an easier life saving the pages with the right name while grabbing them...
find -name '*v_id=*' | perl -lne'rename($_, qq($1.txt)) if /v_id=(\S+)/'
vimv lets you rename multiple files using Vim's text editing capabilities.
Entering vimv opens a Vim window which lists down all files and you can do pattern matching, visual select, etc to edit the names. After you exit Vim, the files will be renamed.
[Disclaimer: I'm the author of the tool]
I'd use ren-regexp, which is a Perl script that lets you mass-rename files very easily.
21:25:11 $ ls
transform.php?dappName=Test&transformer=YAML&v_id=12345
21:25:12 $ ren-regexp 's/transform.php.*v_id=(\d+)/$1.txt/' transform.php*
transform.php?dappName=Test&transformer=YAML&v_id=12345
1 12345.txt
21:26:33 $ ls
12345.txt
This should also work:
prfx='transform.php?dappName=Test&transformer=YAML&v_id='
ls $prfx* | sed s/$prfx// | xargs -Ipsx mv "$prfx"psx psx
this renamer command would do it:
$ renamer --regex --find 'transform.php?dappName=Test&transformer=YAML&v_id=(\w+)' --replace '$1.txt' *
Ok, you need to be able to run a windows binary for this.
But if you can run Total Commander, do this:
Select all files with *, and hit ctrl-M
In the Search field, paste "transform.php?dappName=Test&transformer=YAML&v_id="
(Leave Replace empty)
Press Start
It doesn't get much simpler than that.
You can also rename using regular expressions via this dialog, and you see a realtime preview of how your files are going to be renamed.

Resources