More than one '-e' in sed on OSX - macos

I need to run sed -e 'command' -e 'command' file.txt but I get this error on mac: sed: -e: No such file or directory. Any idea how to fix this?

Works fine with my sed:
$ echo ax | sed -e 's/a/b/' -e 's/x/y/'
by
$ uname -a
Darwin Equinox.local 12.3.0 Darwin Kernel Version 12.3.0: Sun Jan 6 22:37:10 PST 2013; root:xnu-2050.22.13~1/RELEASE_X86_64 x86_64
$ which sed
/usr/bin/sed
So the problem must be elsewhere. Judging by your command given in comments, I would try passing the '' argument to the -i option:
$ sed -i '' -e "s/\.$REGIONID\./\./" -e "/\.$NONREGIONID\./d" application.conf
With the caveat described in the man page:
If a zero-length extension is given, no backup will be saved. It is
not recommended to give a zero-length extension when in-place editing
files, as you risk corruption or partial content in situations where
disk space is exhausted, etc.

Related

xargs doesn't work on SUSE

This problem occurs only on suse, it works on ubuntu and even on windows through babun
My point is to replace a word in several files with another word.
This is what I'm trying:
$ grep -Inrs MY_PATTERN src/ | cut -d: -f1 | xargs sed -i 's/MY_PATTERN/NEW_WORD/g'
sed: can't read path/to/a/found/file_1: No such file or directory
sed: can't read path/to/a/found/file_2: No such file or directory
sed: can't read path/to/a/found/file_3: No such file or directory
...
Knowing that
$ grep -Inrs MY_PATTERN src/ | cut -d: -f1
path/to/a/found/file_1
path/to/a/found/file_2
path/to/a/found/file_3
UPDATE1
This doesn't work either
$ grep -lZ -Irs MY_PATTERN src/ | xargs -0 ls
ls: cannot access path/to/a/found/file_1: No such file or directory
ls: cannot access path/to/a/found/file_2: No such file or directory
ls: cannot access path/to/a/found/file_3: No such file or directory
...
$ ls -al path/to/a/found/file_1 | cat -vet
-rw-r--r-- 1 webme 886 Feb 1 13:36 path/to/a/found/file_1$
UPDATE2
$ whoami
webme
$ uname -a
Linux server_vm_id_34 3.0.101-68-default #1 SMP Tue Dec 1 16:21:37 UTC 2015 (ed01a9f) x86_64 x86_64 x86_64 GNU/Linux
UPDATE3
$ grep --version
grep (GNU grep) 2.7
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Mike Haertel and others, see <http://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>.
$ xargs --version
xargs (GNU findutils) 4.4.0
Copyright (C) 2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Eric B. Decker, James Youngman, and Kevin Dalley.
Built using GNU gnulib version e5573b1bad88bfabcda181b9e0125fb0c52b7d3b
# My project path /home/users/webme/projects/my_project
$ df -T
dl360d-01:/homeweb/users/webme nfs 492625920 461336576 31289344 94% /home/users/webme
$ id
uid=1689(webme) gid=325(web) groups=325(web)
$ mount -v
/dev/vda2 on / type btrfs (rw)
proc on /proc type proc (rw)
sysfs on /sys type sysfs (rw)
debugfs on /sys/kernel/debug type debugfs (rw)
udev on /dev type tmpfs (rw,mode=0755)
tmpfs on /dev/shm type tmpfs (rw,mode=1777)
devpts on /dev/pts type devpts (rw,mode=0620,gid=5)
/dev/vda1 on /boot type ext3 (rw,acl,user_xattr)
/dev/vdb on /appwebinet type xfs (rw)
rpc_pipefs on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw)
dl360d-01:/homeweb/users on /homeweb/users type nfs (rw,soft,bg,addr=xx.xx.xx.xx)
dl360d-01:/appwebinet/tools/list on /appwebinetdev/tools/list type nfs (ro,soft,sloppy,addr=xx.xxx.xx.xx)
dl360d-01:/homeweb/users/webme on /home/users/webme type nfs (rw,soft,bg,addr=xx.xxx.xx.xx)
none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
none on /var/lib/ntp/proc type proc (ro,nosuid,nodev)
I don't have exportfs, neither I have it in sudo zypper install exportfs
I'd suggest keeping it simple:
$ grep -lZ -Irs foo * | xargs -0 sed -i 's/foo/bar/g'
grep -l outputs matching file names only, which is really what you want in this pipeline. grep -Z terminates each matching file name with a NUL, which xargs -0 can pick up. This allows for file names with embedded white-space to pass between the grep and the xargs unfettered.
# show the structure
$ tree
.
└── path
└── to
└── a
└── found
├── file_1
├── file_2
└── file_3
# show the contents
$ grep . path/to/a/found/file_*
path/to/a/found/file_1:a foo bar
path/to/a/found/file_2:a foo bar
path/to/a/found/file_3:a foo bar
# try it out
$ grep -lZ -Irs foo * | xargs -0 ls -l
-rw-rw-r-- 1 bishop bishop 10 Feb 13 09:13 path/to/a/found/file_1
-rw-rw-r-- 1 bishop bishop 10 Feb 13 09:13 path/to/a/found/file_2
-rw-rw-r-- 1 bishop bishop 10 Feb 13 09:13 path/to/a/found/file_3
bishop's helpful answer is the simplest and most robust solution in this case.
This answer may still be of interest for (a) a discussion of the -d vs. the -n options, and (b) how to preview the command(s) that xargs would execute.
From what I understand, SUSE uses GNU utilities, so you can use xargs -d'\n':
grep -Inrs MY_PATTERN src/ | cut -d: -f1 | xargs -d'\n' sed -i 's/MY_PATTERN/NEW_WORD/g'
xargs -d'\n' ensures that each input line as a whole is treated as its own argument (preserving the integrity of filenames with spaces), while still passing as many arguments as possible (typically, all) at once.
(By contrast, -n 1 would break arguments by whitespace, and call the target command with 1 argument at a time.)
If you want to preview the command that would be executed, use an aux. bash command:
grep -Inrs MY_PATTERN src/ | cut -d: -f1 |
xargs -d'\n' bash -c 'printf "%q " "$#"' _ sed -i 's/MY_PATTERN/NEW_WORD/g'
Read on for an explanation.
Optional background information.
xargs has its own option, -p, for previewing the command(s) to execute and prompting for confirmation, but the preview doesn't reflect argument boundaries in the way you'd have to indicate them when calling the command directly from the shell.
A quick example:
$ echo 'hi, there' | xargs -p -d '\n' printf '%s'
printf %s hi, there ?...
What xargs will actually execute is the equivalent of printf '%s' 'hi, there', but that is not reflected in -p's prompt.
Workaround:
$ echo 'hi, there' | xargs -d '\n' bash -c 'printf "%q " "$#"' _ printf '%s'
printf %s hi\,\ there
The generic auxiliary bash command - bash -c 'printf "%q " "$#"' _, inserted just before the target command - quotes the arguments that xargs passes - on demand, only if necessary - in a way that would be required for the shell to recognize each as a single argument, and joins them with spaces.
The net result is that a shell command is printed that is the equivalent of what xargs would execute (though, as you can see, there is no guarantee that the input quoting style is retained).

need help to edit the sudoer on solaris through script

When i am trying in solaris its throughing the below error
# cat /usr/local/etc/sudoers |grep -i unix
unix ALL=(ALL) NOPASSWD: ALL
root on test:
sed -i -e 's/^\s*(unix\sALL=(ALL)\sNOPASSWD:\s*ALL)/#\1/' /usr/local/etc/sudoers
sed: illegal option -- i
root on test:</tmp>
i have tried this also its also not working
root on test: </tmp>
$ sudo perl -pi -e 's/^\s*\(unix\s*ALL=(ALL)\s*NOPASSWD:\s*ALL\)/#\1/' /usr/local/etc/sudoers
root on test: </tmp>
cat /usr/local/etc/sudoers |grep -i unix
unix ALL=(ALL) NOPASSWD: ALL
sed -i -e 's/^\s*\(unix\s*ALL=(ALL)\s*NOPASSWD:\s*ALL\)/#\1/' /usr/local/etc/sudoers but the same script is working on linux

Shell script to make directories and subdirectories with variable names

I'm trying to create script to be run by cron to create multiple folders with subfolders.
DATE=`date +%Y-%m-%d`
IP_ADDR=`ifconfig | grep -v '127.0.0.1' | sed -n 's/.*inet addr:\([0-9.]\+\)\s.*/\1/p'`
/bin/mkdir -p /mnt/db-backup/12/$DATE/$IP_ADDR/
If i run this script manually everything is created as expected. When script is ran by cron subdirectory $IP_ADDR is not created and there is no errors.
I suspect that /sbin is not part of the PATH for the environment that the cron job runs under. You should specify the full path for the ifconfig command:
IP_ADDR=$(/sbin/ifconfig | grep -v '127.0.0.1' | sed -n 's/.*inet addr:\([0-9.]\+\)\s.*/\1/p')
It's also better practice (in general) to use $() for command substitution.
Try to use debug mode :
set -x
DATE=`date +%Y-%m-%d`
IP_ADDR=`ifconfig | grep -v '127.0.0.1' | sed -n 's/.*inet addr:\([0-9.]\+\)\s.*/\1/p'`
/bin/mkdir -p /mnt/db-backup/12/$DATE/$IP_ADDR/
set +x
Then, redirect the output of your cron to a file and have a look, you should find useful information in it.
You are not far off, but there are several ordering caveats that could cause problems. Many systems have different formats for the ifconfig output line. Some with inet xxx.xxx.xxx.xxx, others with inet addr:xxx.xxx.xxx.xxx. (those are the two most common). You may also need to handle the case where there are multiple wired inet interfaces (2+ NICs in the box). However, if you have only 1 NIC, you could try the following to handle the common ifconfig formats:
DATE=`date +%Y-%m-%d`
IP_ADDR=$(ifconfig |
grep -v '127.0.0.1' |
grep -E 'inet[ ](addr:)*[0-9]{1,3}([.][0-9]{1,3}){3}' |
sed -e 's/^.*inet \(addr:\)*//' -e 's/ .*$//')
/bin/mkdir -p /mnt/db-backup/12/$DATE/$IP_ADDR/
or with IP_ADDR written as one line:
IP_ADDR=$(ifconfig | grep -v '127.0.0.1' | grep -E 'inet[ ](addr:)*[0-9]{1,3}([.][0-9]{1,3}){3}' | sed -e 's/^.*inet \(addr:\)*//' -e 's/ .*$//')

bash/shell: easiest way to get kernel name components on command line

On my Fedora machine I sometimes need to find out certain components of the kernel name, e.g.
VERSION=3.18.9-200.fc21
VERSION_ARCH=3.18.9-200.fc21.x86_64
SHORT_VERSION=3.18
DIST_VERSION=fc21
EXTRAVERSION = -200.fc21.x86_64
I know uname -a/-r/-m but these give me not all the components I need.
Of course I can just disassemble uname -r e.g.
KERNEL_VERSION_ARCH=$(uname -r)
KERNEL_VERSION=$(uname -r | cut -d '.' -f 1-4)
KERNEL_SHORT_VERSION=$(uname -r | cut -d '.' -f 1-2)
KERNEL_DIST_VERSION=$(uname -r | cut -d '.' -f 4)
EXTRAVERSION="-$(uname -r | cut -d '-' -f 2)"
But this seems very cumbersome and not future-safe to me.
Question: is there an elegant way (i.e. more readable and distribution aware) to get all kernel version/name components I need?
Nice would be s.th. like
kernel-ver -f "%M.%m.%p-%e.%a"
3.19.4-200.fc21.x86_64
kernel-ver -f "%M.%m"
3.19
kernel-ver -f "%d"
fc21
Of course the uname -r part would need a bit sed/awk/grep magic. But there are some other options you can try:
cat /etc/os-release
cat /etc/lsb-release
Since it's fedora you can try: cat /etc/fedora-release
lsb_release -a is also worth a try.
cat /proc/version, but that nearly the same output as uname -a
In the files /etc/*-release the format is already VARIABLE=value, so you could source the file directly and access the variables later:
$ source /etc/os-release
$ echo $ID
fedora
To sum this up a command that should work on every system that combines the above ideas:
cat /etc/*_ver* /etc/*-rel* 2>/dev/null

Strange behavior of uniq on darwin shells

I've used 'uniq -d -c file' in many shell scripts on linux machines, and it works.
On my MAC (OS X 10.6.7 with developer tools installed) it doesn't seems to work:
$ uniq -d -c testfile.txt
usage: uniq [-c | -d | -u] [-i] [-f fields] [-s chars] [input [output]]
It would be nice if anyone could checks this.
Well, it's right there in the Usage message. [ -c | -d | -u] means you can use one of those possibilities, not two.
Since OSX is based on BSD, you can check that here or, thanks to Ignacio, the more Apple-specific one here.
If you want to achieve a similar output, you could use:
do_your_thing | uniq -c | grep -v '^ *1 '
which will strip out all those coalesced lines that have a count of one.
You can try this awk solution
awk '{a[$0]++}END{for(i in a)if(a[i]>1){ print i ,a[i] } }' file

Resources